Initial commit
This commit is contained in:
1
engines/cruise/POTFILES
Normal file
1
engines/cruise/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/cruise/metaengine.cpp
|
||||
926
engines/cruise/actor.cpp
Normal file
926
engines/cruise/actor.cpp
Normal file
@@ -0,0 +1,926 @@
|
||||
/* 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/textconsole.h"
|
||||
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/staticres.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
enum AnimPathIds {
|
||||
ANIM_WAIT = -1,
|
||||
ANIM_FINISH = -2,
|
||||
ANIM_STATIC = -3
|
||||
};
|
||||
|
||||
bool isAnimFinished(int overlayIdx, int idx, actorStruct *pStartEntry, int objType) {
|
||||
actorStruct *pCurrentEntry = pStartEntry->next;
|
||||
|
||||
while (pCurrentEntry) {
|
||||
if ((pCurrentEntry->overlayNumber == overlayIdx || overlayIdx == -1) &&
|
||||
(pCurrentEntry->idx == idx || idx == -1) &&
|
||||
(pCurrentEntry->type == objType || objType == -1)) {
|
||||
if (pCurrentEntry->pathId != ANIM_FINISH) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pCurrentEntry = pCurrentEntry->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
actorStruct *findActor(actorStruct *pStartEntry, int overlayIdx, int objIdx, int type) {
|
||||
actorStruct *pCurrentEntry = pStartEntry->next;
|
||||
|
||||
while (pCurrentEntry) {
|
||||
if ((pCurrentEntry->overlayNumber == overlayIdx
|
||||
|| overlayIdx == -1) && (pCurrentEntry->idx == objIdx
|
||||
|| objIdx == -1) && (pCurrentEntry->type == type
|
||||
|| type == -1)) {
|
||||
return pCurrentEntry;
|
||||
}
|
||||
|
||||
pCurrentEntry = pCurrentEntry->next;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int nclick_noeud;
|
||||
int flag_aff_chemin;
|
||||
|
||||
void getPixel(int x, int y) {
|
||||
|
||||
for (uint i = 0; i < _vm->_polyStructs->size(); ++i) {
|
||||
CtStruct &ct = (*_vm->_polyStructs)[i];
|
||||
numPoly = ct.num;
|
||||
|
||||
if (walkboxState[numPoly] == 0 && ct.bounds.contains(x, y)) {
|
||||
// click was in given box
|
||||
int u = y - ct.bounds.top;
|
||||
CtEntry &cte = ct.slices[u];
|
||||
|
||||
if ((x >= cte.minX && x <= cte.maxX)) {
|
||||
flag_obstacle = walkboxColor[numPoly];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flag_obstacle = 0;
|
||||
}
|
||||
|
||||
int x_mouse;
|
||||
int y_mouse;
|
||||
|
||||
int point_select;
|
||||
|
||||
int table_ptselect[2][2];
|
||||
|
||||
int X;
|
||||
int Y;
|
||||
|
||||
int modelVar9;
|
||||
int modelVar10;
|
||||
|
||||
void polydroite(int x1, int y1, int x2, int y2) {
|
||||
int dx;
|
||||
int dy;
|
||||
|
||||
int mD0;
|
||||
int mD1;
|
||||
|
||||
int mA0;
|
||||
int mA1;
|
||||
|
||||
int bp;
|
||||
int cx;
|
||||
int si;
|
||||
|
||||
int ax;
|
||||
int bx;
|
||||
|
||||
modelVar9 = x1;
|
||||
modelVar10 = y1;
|
||||
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
|
||||
mD0 = mD1 = 1;
|
||||
|
||||
if (dx < 0) {
|
||||
dx = -dx;
|
||||
mD0 = -1;
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
dy = -dy;
|
||||
mD1 = -1;
|
||||
}
|
||||
|
||||
if (dx < dy) {
|
||||
mA0 = 0;
|
||||
bp = dx;
|
||||
cx = dy;
|
||||
|
||||
mA1 = mD1;
|
||||
} else {
|
||||
mA1 = 0;
|
||||
bp = dy;
|
||||
cx = dx;
|
||||
|
||||
mA0 = mD0;
|
||||
}
|
||||
|
||||
bp = bp * 2;
|
||||
dx = bp - cx;
|
||||
si = dx - cx;
|
||||
|
||||
ax = modelVar9;
|
||||
bx = modelVar10;
|
||||
|
||||
getPixel(modelVar9, modelVar10);
|
||||
|
||||
X = modelVar9;
|
||||
Y = modelVar10;
|
||||
|
||||
if ((flag_obstacle == 0) || (cx == 0)) {
|
||||
flag_obstacle = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
while (--cx >= 0) {
|
||||
if (dx > 0) {
|
||||
ax += mD0;
|
||||
bx += mD1;
|
||||
dx += si;
|
||||
} else {
|
||||
ax += mA0;
|
||||
bx += mA1;
|
||||
dx += bp;
|
||||
}
|
||||
|
||||
getPixel(ax, bx);
|
||||
|
||||
X = ax;
|
||||
Y = bx;
|
||||
|
||||
if (flag_obstacle == 0) {
|
||||
flag_obstacle = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
flag_obstacle = 0;
|
||||
}
|
||||
|
||||
void poly2(int x1, int y1, int x2, int y2) {
|
||||
int dx;
|
||||
int dy;
|
||||
|
||||
int mD0;
|
||||
int mD1;
|
||||
|
||||
int mA0;
|
||||
int mA1;
|
||||
|
||||
int bp;
|
||||
int cx;
|
||||
int si;
|
||||
|
||||
int ax;
|
||||
int bx;
|
||||
|
||||
modelVar9 = x1;
|
||||
modelVar10 = y1;
|
||||
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
|
||||
mD0 = mD1 = 1;
|
||||
|
||||
if (dx < 0) {
|
||||
dx = -dx;
|
||||
mD0 = -1;
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
dy = -dy;
|
||||
mD1 = -1;
|
||||
}
|
||||
|
||||
if (dx < dy) {
|
||||
mA0 = 0;
|
||||
bp = dx;
|
||||
cx = dy;
|
||||
|
||||
mA1 = mD1;
|
||||
} else {
|
||||
mA1 = 0;
|
||||
bp = dy;
|
||||
cx = dx;
|
||||
|
||||
mA0 = mD0;
|
||||
}
|
||||
|
||||
bp = bp * 2;
|
||||
dx = bp - cx;
|
||||
si = dx - cx;
|
||||
|
||||
ax = modelVar9;
|
||||
bx = modelVar10;
|
||||
|
||||
getPixel(modelVar9, modelVar10);
|
||||
|
||||
X = modelVar9;
|
||||
Y = modelVar10;
|
||||
|
||||
if ((flag_obstacle != 0) || (cx == 0)) {
|
||||
flag_obstacle = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
while (--cx >= 0) {
|
||||
if (dx > 0) {
|
||||
ax += mD0;
|
||||
bx += mD1;
|
||||
dx += si;
|
||||
} else {
|
||||
ax += mA0;
|
||||
bx += mA1;
|
||||
dx += bp;
|
||||
}
|
||||
|
||||
getPixel(ax, bx);
|
||||
|
||||
X = ax;
|
||||
Y = bx;
|
||||
|
||||
if (flag_obstacle != 0) {
|
||||
flag_obstacle = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
flag_obstacle = 0;
|
||||
}
|
||||
|
||||
int point_proche(int16 table[][2]) {
|
||||
int d1 = 1000;
|
||||
|
||||
_vm->_polyStructs = &_vm->_polyStructNorm;
|
||||
|
||||
if (nclick_noeud == 1) {
|
||||
int x = x_mouse;
|
||||
int y = y_mouse;
|
||||
int x1 = table_ptselect[0][0];
|
||||
int y1 = table_ptselect[0][1];
|
||||
|
||||
_vm->_polyStructs = &_vm->_polyStructExp;
|
||||
|
||||
getPixel(x, y);
|
||||
|
||||
if (!flag_obstacle) {
|
||||
_vm->_polyStructs = &_vm->_polyStructNorm;
|
||||
|
||||
getPixel(x, y);
|
||||
|
||||
if (flag_obstacle) {
|
||||
polydroite(x1, y1, x, y);
|
||||
}
|
||||
_vm->_polyStructs = &_vm->_polyStructExp;
|
||||
}
|
||||
if (!flag_obstacle) { /* dans flag_obstacle --> couleur du point */
|
||||
x1 = table_ptselect[0][0];
|
||||
y1 = table_ptselect[0][1];
|
||||
|
||||
poly2(x, y, x1, y1);
|
||||
|
||||
x_mouse = X;
|
||||
y_mouse = Y;
|
||||
}
|
||||
}
|
||||
_vm->_polyStructs = &_vm->_polyStructNorm;
|
||||
|
||||
int p = -1;
|
||||
for (int i = 0; i < ctp_routeCoordCount; i++) {
|
||||
int x = table[i][0];
|
||||
int y = table[i][1];
|
||||
|
||||
int pointDistance = computeDistance(x_mouse, y_mouse, x, y);
|
||||
if (pointDistance < d1) {
|
||||
polydroite(x_mouse, y_mouse, x, y);
|
||||
|
||||
if (!flag_obstacle && ctp_routes[i][0] > 0) {
|
||||
d1 = pointDistance;
|
||||
p = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
#define NBNOEUD 20
|
||||
|
||||
int16 select_noeud[3];
|
||||
int8 solution[20 + 1];
|
||||
|
||||
int prem;
|
||||
int prem2;
|
||||
int dist_chemin;
|
||||
int idsol;
|
||||
int solmax;
|
||||
|
||||
int8 fl[NBNOEUD + 1];
|
||||
int8 sol[NBNOEUD + 1];
|
||||
int8 Fsol[NBNOEUD + 1];
|
||||
|
||||
int D;
|
||||
|
||||
void explore(int depart, int arrivee) {
|
||||
int id1 = depart;
|
||||
|
||||
fl[id1]++;
|
||||
sol[idsol++] = (char)id1;
|
||||
|
||||
if (idsol > solmax) {
|
||||
fl[id1] = -1;
|
||||
idsol--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
while ((i = fl[id1]) < 20) {
|
||||
int id2 = ctp_routes[id1][i + 1];
|
||||
|
||||
if (id2 == arrivee) {
|
||||
if (idsol < solmax) {
|
||||
sol[idsol] = (char)arrivee;
|
||||
D = 0;
|
||||
for (i = 0; i < idsol; i++) {
|
||||
D = D + distanceTable[(int)sol[i]][(int)sol[i + 1]];
|
||||
Fsol[i] = sol[i];
|
||||
}
|
||||
prem2 = 0;
|
||||
if (!prem) {
|
||||
dist_chemin = D;
|
||||
prem = 1;
|
||||
for (i = 0; i <= idsol; i++) {
|
||||
solution[i] = sol[i];
|
||||
}
|
||||
solution[i++] = -1;
|
||||
solution[i] = -1;
|
||||
} else if (D < dist_chemin) {
|
||||
dist_chemin = D;
|
||||
for (i = 0; i <= idsol; i++) {
|
||||
solution[i] = sol[i];
|
||||
}
|
||||
solution[i++] = -1;
|
||||
solution[i] = -1;
|
||||
}
|
||||
}
|
||||
fl[id1] = -1;
|
||||
idsol--;
|
||||
|
||||
return;
|
||||
} else if ((id2 != -1) && ((int)fl[id2] == -1))
|
||||
explore(id2, arrivee);
|
||||
else if (id2 == -1) {
|
||||
fl[id1] = -1;
|
||||
idsol--;
|
||||
|
||||
return;
|
||||
}
|
||||
fl[id1]++;
|
||||
}
|
||||
|
||||
fl[id1] = -1;
|
||||
idsol--;
|
||||
}
|
||||
|
||||
void chemin0(int depart, int arrivee) {
|
||||
prem = 0;
|
||||
prem2 = 0;
|
||||
dist_chemin = 0;
|
||||
idsol = 0;
|
||||
solmax = 999;
|
||||
|
||||
for (int i = 0; i < 20 + 1; i++)
|
||||
fl[i] = -1;
|
||||
|
||||
X = 0;
|
||||
Y = 30;
|
||||
|
||||
explore(depart, arrivee);
|
||||
}
|
||||
|
||||
void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2]) {
|
||||
table[*nclick] = p;
|
||||
table[(*nclick) + 1] = -1;
|
||||
table_ptselect[*nclick][0] = x_mouse;
|
||||
table_ptselect[*nclick][1] = y_mouse;
|
||||
(*nclick)++;
|
||||
_vm->_polyStructs = &_vm->_polyStructNorm;
|
||||
|
||||
if (*nclick == 2) { // second point
|
||||
int x1 = table_ptselect[0][0];
|
||||
int y1 = table_ptselect[0][1];
|
||||
int x2 = table_ptselect[1][0];
|
||||
int y2 = table_ptselect[1][1];
|
||||
if ((x1 == x2) && (y1 == y2)) {
|
||||
return;
|
||||
}
|
||||
flag_aff_chemin = 1;
|
||||
_vm->_polyStructs = &_vm->_polyStructExp;
|
||||
|
||||
// can we go there directly ?
|
||||
polydroite(x1, y1, x2, y2);
|
||||
|
||||
if (!flag_obstacle) {
|
||||
solution0[0][0] = x1;
|
||||
solution0[0][1] = y1;
|
||||
_vm->_polyStructs = &_vm->_polyStructExp;
|
||||
|
||||
poly2(x2, y2, ctp_routeCoords[select_noeud[1]][0],
|
||||
ctp_routeCoords[select_noeud[1]][1]);
|
||||
|
||||
solution0[1][0] = table_ptselect[1][0] = X;
|
||||
solution0[1][1] = table_ptselect[1][1] = Y;
|
||||
solution0[2][0] = -1;
|
||||
|
||||
if ((x1 == X) && (y1 == Y)) {
|
||||
flag_aff_chemin = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// no, we take the fastest way
|
||||
solution[0] = -1;
|
||||
if (ctp_routes[select_noeud[0]][0] > 0)
|
||||
chemin0(table[0], table[1]);
|
||||
|
||||
if (solution[0] == -1) {
|
||||
x1 = table_ptselect[0][0];
|
||||
y1 = table_ptselect[0][1];
|
||||
polydroite(x1, y1, x_mouse, y_mouse);
|
||||
solution0[0][0] = x1;
|
||||
solution0[0][1] = y1;
|
||||
solution0[1][0] = X;
|
||||
solution0[1][1] = Y;
|
||||
|
||||
solution0[2][0] = -1;
|
||||
if ((x1 == X) && (y1 == Y)) {
|
||||
flag_aff_chemin = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
solution0[0][0] = x1;
|
||||
solution0[0][1] = y1;
|
||||
int i = 0;
|
||||
while (solution[i] != -1) {
|
||||
int p1 = solution[i];
|
||||
solution0[i + 1][0] = ctp_routeCoords[p1][0];
|
||||
solution0[++i][1] = ctp_routeCoords[p1][1];
|
||||
}
|
||||
_vm->_polyStructs = &_vm->_polyStructExp;
|
||||
poly2(x2, y2,
|
||||
ctp_routeCoords[select_noeud[1]][0],
|
||||
ctp_routeCoords[select_noeud[1]][1]);
|
||||
solution0[i + 1][0] = table_ptselect[1][0] = X;
|
||||
solution0[i + 1][1] = table_ptselect[1][1] = Y;
|
||||
solution0[i + 2][0] = -1;
|
||||
if ((x1 == X) && (y1 == Y)) {
|
||||
flag_aff_chemin = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/****** Trim down any un-necessary walk points ******/
|
||||
|
||||
i++;
|
||||
int d = 0;
|
||||
int a = i;
|
||||
flag_obstacle = 1;
|
||||
while (d != a) {
|
||||
x1 = solution0[d][0];
|
||||
y1 = solution0[d][1];
|
||||
|
||||
while (flag_obstacle && i != d) {
|
||||
x2 = solution0[i][0];
|
||||
y2 = solution0[i][1];
|
||||
_vm->_polyStructs = &_vm->_polyStructExp;
|
||||
polydroite(x1, y1, x2, y2);
|
||||
i--;
|
||||
}
|
||||
flag_obstacle = 1;
|
||||
if (d != i) {
|
||||
i++;
|
||||
for (int b = d + 1; b < i; b++) {
|
||||
solution0[b][0] = -2;
|
||||
}
|
||||
} else
|
||||
i++;
|
||||
d = i;
|
||||
i = a;
|
||||
}
|
||||
flag_obstacle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a path for an actor to walk between a given source and destination position
|
||||
*/
|
||||
int16 computePathfinding(MovementEntry &moveInfo, int16 x, int16 y, int16 destX, int16 destY, int16 stepX, int16 stepY, int16 oldPathId) {
|
||||
persoStruct *perso;
|
||||
int num;
|
||||
|
||||
if (!_vm->_polyStruct) {
|
||||
moveInfo.x = -1;
|
||||
moveInfo.y = -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (oldPathId >= 0) {
|
||||
if (persoTable[oldPathId]) {
|
||||
freePerso(oldPathId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!flagCt) {
|
||||
int16 *ptr;
|
||||
int i = 0;
|
||||
for (; i < NUM_PERSONS; i++) { // 10 = num perso
|
||||
if (!persoTable[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == NUM_PERSONS) {
|
||||
moveInfo.x = -1;
|
||||
moveInfo.y = -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
perso = persoTable[i] = (persoStruct *) MemAlloc(sizeof(persoStruct));
|
||||
|
||||
ptr = perso->solution[0];
|
||||
|
||||
perso->inc_jo1 = stepX;
|
||||
perso->inc_jo2 = stepY;
|
||||
|
||||
*(ptr++) = x;
|
||||
*(ptr++) = y;
|
||||
*(ptr++) = moveInfo.x = destX;
|
||||
*(ptr++) = moveInfo.y = destY;
|
||||
*(ptr++) = -1;
|
||||
|
||||
moveInfo.poly = numPoly;
|
||||
|
||||
perso->inc_droite = 0;
|
||||
perso->inc_chemin = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
nclick_noeud = 0;
|
||||
_vm->_polyStructs = &_vm->_polyStructNorm;
|
||||
flag_aff_chemin = 0;
|
||||
|
||||
if (x == destX && y == destY) {
|
||||
moveInfo.x = -1;
|
||||
moveInfo.y = -1;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/******* cherche le premier noeud ******/
|
||||
|
||||
getPixel(x, y);
|
||||
|
||||
moveInfo.poly = numPoly;
|
||||
|
||||
x_mouse = x;
|
||||
y_mouse = y;
|
||||
|
||||
if (!flag_obstacle || (point_select = point_proche(ctp_routeCoords)) == -1) {
|
||||
moveInfo.x = -1;
|
||||
moveInfo.y = -1;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
valide_noeud(select_noeud, point_select, &nclick_noeud, nullptr);
|
||||
|
||||
flag_aff_chemin = 0;
|
||||
|
||||
/******* cherche le deuxieme noeud ******/
|
||||
|
||||
num = 0;
|
||||
while (num < NUM_PERSONS && persoTable[num] != nullptr)
|
||||
num++;
|
||||
|
||||
if (num == NUM_PERSONS) {
|
||||
moveInfo.x = -1;
|
||||
moveInfo.y = -1;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
perso = persoTable[num] = (persoStruct *) MemAlloc(sizeof(persoStruct));
|
||||
|
||||
perso->inc_jo1 = stepX;
|
||||
perso->inc_jo2 = stepY;
|
||||
|
||||
x_mouse = destX;
|
||||
y_mouse = destY;
|
||||
|
||||
if ((point_select = point_proche(ctp_routeCoords)) != -1)
|
||||
valide_noeud(select_noeud, point_select, &nclick_noeud, perso->solution);
|
||||
|
||||
if ((!flag_aff_chemin) || ((table_ptselect[0][0] == table_ptselect[1][0]) && (table_ptselect[0][1] == table_ptselect[1][1]))) {
|
||||
moveInfo.x = -1;
|
||||
moveInfo.y = -1;
|
||||
freePerso(num);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
moveInfo.x = table_ptselect[1][0];
|
||||
moveInfo.y = table_ptselect[1][1];
|
||||
moveInfo.poly = numPoly;
|
||||
perso->inc_chemin = 0;
|
||||
perso->inc_droite = 0;
|
||||
|
||||
return (num);
|
||||
}
|
||||
|
||||
void set_anim(int ovl, int obj, int start, int x, int y, int mat, int state) {
|
||||
int newf, zoom;
|
||||
|
||||
newf = ABS(mat) - 1;
|
||||
|
||||
zoom = computeZoom(y);
|
||||
if (mat < 0)
|
||||
zoom = -zoom;
|
||||
|
||||
setObjectPosition(ovl, obj, 0, x);
|
||||
setObjectPosition(ovl, obj, 1, y);
|
||||
setObjectPosition(ovl, obj, 2, y);
|
||||
setObjectPosition(ovl, obj, 4, zoom);
|
||||
setObjectPosition(ovl, obj, 3, newf + start);
|
||||
setObjectPosition(ovl, obj, 5, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the processing of any active actors to allow for handling movement
|
||||
*/
|
||||
void processAnimation() {
|
||||
objectParamsQuery params;
|
||||
MovementEntry moveInfo;
|
||||
actorStruct *currentActor = actorHead.next;
|
||||
actorStruct *nextActor;
|
||||
|
||||
while (currentActor) {
|
||||
nextActor = currentActor->next;
|
||||
|
||||
if (!currentActor->freeze && ((currentActor->type == ATP_MOUSE) || (currentActor->type == 1))) {
|
||||
getMultipleObjectParam(currentActor->overlayNumber, currentActor->idx, ¶ms);
|
||||
|
||||
if (((animationStart && !currentActor->flag) || (!animationStart && currentActor->x_dest != -1
|
||||
&& currentActor->y_dest != -1)) && (currentActor->type == ATP_MOUSE)) {
|
||||
// mouse animation
|
||||
if (!animationStart) {
|
||||
aniX = currentActor->x_dest;
|
||||
aniY = currentActor->y_dest;
|
||||
currentActor->x_dest = -1;
|
||||
currentActor->y_dest = -1;
|
||||
|
||||
currentActor->flag = 1;
|
||||
}
|
||||
|
||||
currentActor->pathId = computePathfinding(moveInfo, params.X, params.Y,
|
||||
aniX, aniY, currentActor->stepX, currentActor->stepY, currentActor->pathId);
|
||||
|
||||
if (currentActor->pathId == ANIM_WAIT) {
|
||||
if ((currentActor->endDirection != -1) && (currentActor->endDirection != currentActor->startDirection)) {
|
||||
currentActor->phase = ANIM_PHASE_STATIC_END;
|
||||
currentActor->nextDirection = currentActor->endDirection;
|
||||
currentActor->endDirection = -1;
|
||||
currentActor->counter = 0;
|
||||
} else {
|
||||
currentActor->pathId = ANIM_FINISH;
|
||||
currentActor->flag = 0;
|
||||
currentActor->endDirection = -1;
|
||||
currentActor->phase = ANIM_PHASE_WAIT;
|
||||
}
|
||||
} else {
|
||||
currentActor->phase = ANIM_PHASE_STATIC;
|
||||
currentActor->counter = -1;
|
||||
}
|
||||
} else
|
||||
if ((currentActor->type == 1) && (currentActor->x_dest != -1) && (currentActor->y_dest != -1)) {
|
||||
// track animation
|
||||
currentActor->pathId = computePathfinding(moveInfo, params.X, params.Y, currentActor->x_dest, currentActor->y_dest, currentActor->stepX, currentActor->stepY, currentActor->pathId);
|
||||
|
||||
currentActor->x_dest = -1;
|
||||
currentActor->y_dest = -1;
|
||||
|
||||
if (currentActor->pathId == ANIM_WAIT) {
|
||||
if ((currentActor->endDirection != -1) && (currentActor->endDirection != currentActor->startDirection)) {
|
||||
currentActor->phase = ANIM_PHASE_STATIC_END;
|
||||
currentActor->nextDirection = currentActor->endDirection;
|
||||
currentActor->endDirection = -1;
|
||||
currentActor->counter = 0;
|
||||
} else {
|
||||
currentActor->pathId = -2;
|
||||
currentActor->flag = 0;
|
||||
currentActor->endDirection = -1;
|
||||
currentActor->phase = ANIM_PHASE_WAIT;
|
||||
}
|
||||
} else {
|
||||
currentActor->phase = ANIM_PHASE_STATIC;
|
||||
currentActor->counter = -1;
|
||||
}
|
||||
}
|
||||
|
||||
animationStart = false;
|
||||
|
||||
if ((currentActor->pathId >= 0) || (currentActor->phase == ANIM_PHASE_STATIC_END)) {
|
||||
|
||||
// Main switch statement for handling various phases of movement
|
||||
// IMPORTANT: This switch relies on falling through cases in certain circumstances
|
||||
// , so 'break' statements should *not* be used at the end of case areas
|
||||
switch (currentActor->phase) {
|
||||
case ANIM_PHASE_STATIC_END:
|
||||
case ANIM_PHASE_STATIC:
|
||||
{
|
||||
// In-place (on the spot) animationos
|
||||
|
||||
if ((currentActor->counter == -1) && (currentActor->phase == ANIM_PHASE_STATIC)) {
|
||||
affiche_chemin(currentActor->pathId, moveInfo);
|
||||
|
||||
if (moveInfo.x == -1) {
|
||||
currentActor->pathId = ANIM_FINISH;
|
||||
currentActor->flag = 0;
|
||||
currentActor->endDirection = -1;
|
||||
currentActor->phase = ANIM_PHASE_WAIT;
|
||||
break;
|
||||
}
|
||||
|
||||
currentActor->x = moveInfo.x;
|
||||
currentActor->y = moveInfo.y;
|
||||
currentActor->nextDirection = moveInfo.direction;
|
||||
currentActor->poly = moveInfo.poly;
|
||||
currentActor->counter = 0;
|
||||
|
||||
if (currentActor->startDirection == currentActor->nextDirection)
|
||||
currentActor->phase = ANIM_PHASE_MOVE;
|
||||
}
|
||||
|
||||
if ((currentActor->counter >= 0)
|
||||
&& ((currentActor->phase == ANIM_PHASE_STATIC_END)
|
||||
|| (currentActor->phase == ANIM_PHASE_STATIC))) {
|
||||
int newA;
|
||||
int inc = 1;
|
||||
int t_inc = currentActor->startDirection - 1;
|
||||
|
||||
if (t_inc < 0)
|
||||
t_inc = 3;
|
||||
|
||||
if (currentActor->nextDirection == t_inc)
|
||||
inc = -1;
|
||||
|
||||
if (inc > 0)
|
||||
newA = actor_stat[currentActor->startDirection][currentActor->counter++];
|
||||
else
|
||||
newA = actor_invstat[currentActor->startDirection][currentActor->counter++];
|
||||
|
||||
if (newA == 0) {
|
||||
currentActor->startDirection = currentActor->startDirection + inc;
|
||||
|
||||
if (currentActor->startDirection > 3)
|
||||
currentActor->startDirection = 0;
|
||||
|
||||
if (currentActor->startDirection < 0)
|
||||
currentActor-> startDirection = 3;
|
||||
|
||||
currentActor->counter = 0;
|
||||
|
||||
if (currentActor->startDirection == currentActor->nextDirection) {
|
||||
if (currentActor->phase == ANIM_PHASE_STATIC)
|
||||
currentActor->phase = ANIM_PHASE_MOVE;
|
||||
else
|
||||
currentActor->phase = ANIM_PHASE_END;
|
||||
} else {
|
||||
newA = actor_stat[currentActor->startDirection][currentActor->counter++];
|
||||
|
||||
if (inc == -1)
|
||||
newA = -newA;
|
||||
|
||||
set_anim(currentActor->overlayNumber, currentActor->idx,
|
||||
currentActor->start, params.X, params.Y, newA, currentActor->poly);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
set_anim(currentActor->overlayNumber,currentActor->idx, currentActor->start,
|
||||
params.X, params.Y, newA, currentActor->poly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// fall through
|
||||
|
||||
case ANIM_PHASE_MOVE:
|
||||
{
|
||||
// Walk animations
|
||||
|
||||
if (currentActor->counter >= 1) {
|
||||
affiche_chemin(currentActor->pathId, moveInfo);
|
||||
|
||||
if (moveInfo.x == -1) {
|
||||
if ((currentActor->endDirection == -1) || (currentActor->endDirection == currentActor->nextDirection)) {
|
||||
currentActor->phase = ANIM_PHASE_END;
|
||||
} else {
|
||||
currentActor->phase = ANIM_PHASE_STATIC_END;
|
||||
currentActor->nextDirection = currentActor->endDirection;
|
||||
}
|
||||
currentActor->counter = 0;
|
||||
break;
|
||||
} else {
|
||||
currentActor->x = moveInfo.x;
|
||||
currentActor->y = moveInfo.y;
|
||||
currentActor->nextDirection = moveInfo.direction;
|
||||
currentActor->poly = moveInfo.poly;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentActor->phase == ANIM_PHASE_MOVE) {
|
||||
int newA;
|
||||
|
||||
currentActor->startDirection = currentActor->nextDirection;
|
||||
|
||||
newA = actor_move[currentActor->startDirection][currentActor->counter++];
|
||||
if (!newA) {
|
||||
currentActor->counter = 0;
|
||||
newA = actor_move[currentActor->startDirection][currentActor->counter++];
|
||||
}
|
||||
set_anim(currentActor->overlayNumber, currentActor->idx, currentActor->start,
|
||||
currentActor->x, currentActor->y, newA, currentActor->poly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fall through
|
||||
|
||||
case ANIM_PHASE_END:
|
||||
{
|
||||
// End of walk animation
|
||||
|
||||
int newA = actor_end[currentActor->startDirection][0];
|
||||
|
||||
set_anim(currentActor->overlayNumber, currentActor->idx, currentActor->start,
|
||||
currentActor->x, currentActor->y, newA, currentActor->poly);
|
||||
|
||||
currentActor->pathId = ANIM_FINISH;
|
||||
currentActor->phase = ANIM_PHASE_WAIT;
|
||||
currentActor->flag = 0;
|
||||
currentActor->endDirection = -1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
warning("Unimplemented currentActor->phase=%d in processAnimation()", currentActor->phase);
|
||||
// exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentActor = nextActor;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
72
engines/cruise/actor.h
Normal file
72
engines/cruise/actor.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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 CRUISE_ACTOR_H
|
||||
#define CRUISE_ACTOR_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
enum animPhase {
|
||||
ANIM_PHASE_WAIT = 0,
|
||||
ANIM_PHASE_STATIC = 1,
|
||||
ANIM_PHASE_MOVE = 2,
|
||||
ANIM_PHASE_STATIC_END = 3,
|
||||
ANIM_PHASE_END = 4
|
||||
};
|
||||
|
||||
enum ATP {
|
||||
ATP_MOUSE = 0,
|
||||
ATP_TRACK = 1
|
||||
};
|
||||
|
||||
struct actorStruct {
|
||||
struct actorStruct *next;
|
||||
struct actorStruct *prev;
|
||||
|
||||
int16 idx;
|
||||
int16 type;
|
||||
int16 overlayNumber;
|
||||
int16 x_dest;
|
||||
int16 y_dest;
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 startDirection;
|
||||
int16 nextDirection;
|
||||
int16 endDirection;
|
||||
int16 stepX;
|
||||
int16 stepY;
|
||||
int16 pathId;
|
||||
animPhase phase;
|
||||
int16 counter;
|
||||
int16 poly;
|
||||
int16 flag;
|
||||
int16 start;
|
||||
int16 freeze;
|
||||
};
|
||||
|
||||
bool isAnimFinished(int overlayIdx, int idx, actorStruct *pStartEntry, int objType);
|
||||
actorStruct *findActor(actorStruct *pStartEntry, int overlayIdx, int objIdx, int type);
|
||||
void processAnimation();
|
||||
void getPixel(int x, int y);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
230
engines/cruise/background.cpp
Normal file
230
engines/cruise/background.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/* 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/textconsole.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/cruise.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
uint8 colorMode = 0;
|
||||
|
||||
uint8 *backgroundScreens[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; // wasn't initialized in original, but it's probably better
|
||||
bool backgroundChanged[8] = { false, false, false, false, false, false, false, false };
|
||||
backgroundTableStruct backgroundTable[8];
|
||||
|
||||
char hwPage[64000];
|
||||
|
||||
char *hwMemAddr[] = {
|
||||
hwPage,
|
||||
};
|
||||
|
||||
short int cvtPalette[0x20];
|
||||
|
||||
int loadMEN(uint8 **ptr) {
|
||||
char *localPtr = (char *) * ptr;
|
||||
|
||||
if (!strcmp(localPtr, "MEN")) {
|
||||
localPtr += 4;
|
||||
|
||||
titleColor = *(localPtr++);
|
||||
selectColor = *(localPtr++);
|
||||
itemColor = *(localPtr++);
|
||||
subColor = *(localPtr++);
|
||||
|
||||
*ptr = (uint8 *) localPtr;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CVTLoaded;
|
||||
|
||||
int loadCVT(uint8 **ptr) {
|
||||
char *localPtr = (char *) * ptr;
|
||||
|
||||
if (!strcmp(localPtr, "CVT")) {
|
||||
localPtr += 4;
|
||||
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
cvtPalette[i] = *(localPtr++);
|
||||
|
||||
*ptr = (uint8 *) localPtr;
|
||||
|
||||
CVTLoaded = 1;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
CVTLoaded = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern int lastFileSize;
|
||||
|
||||
int loadBackground(const char *name, int idx) {
|
||||
uint8 *ptr;
|
||||
uint8 *ptr2;
|
||||
uint8 *ptrToFree;
|
||||
|
||||
debug(1, "Loading BG: %s", name);
|
||||
|
||||
// WORKAROUND: Don't allow saving during endgame
|
||||
if (!strcmp(name, "DGF1.PI1")) {
|
||||
userEnabled = false;
|
||||
}
|
||||
|
||||
if (!backgroundScreens[idx]) {
|
||||
backgroundScreens[idx] = (uint8 *)mallocAndZero(320 * 200);
|
||||
}
|
||||
|
||||
if (!backgroundScreens[idx]) {
|
||||
backgroundTable[idx].name[0] = 0;
|
||||
return (-2);
|
||||
}
|
||||
|
||||
backgroundChanged[idx] = true;
|
||||
|
||||
ptrToFree = gfxModuleData.pPage10;
|
||||
if (loadFileSub1(&ptrToFree, name, nullptr) < 0) {
|
||||
if (ptrToFree != gfxModuleData.pPage10)
|
||||
MemFree(ptrToFree);
|
||||
|
||||
return (-18);
|
||||
}
|
||||
|
||||
if (lastFileSize == 32078 || lastFileSize == 32080 || lastFileSize == 32034) {
|
||||
colorMode = 0;
|
||||
} else {
|
||||
colorMode = 1;
|
||||
}
|
||||
|
||||
ptr = ptrToFree;
|
||||
ptr2 = ptrToFree;
|
||||
|
||||
if (!strcmp(name, "LOGO.PI1")) {
|
||||
oldSpeedGame = speedGame;
|
||||
flagSpeed = 1;
|
||||
speedGame = 1;
|
||||
} else if (flagSpeed) {
|
||||
speedGame = oldSpeedGame;
|
||||
flagSpeed = 0;
|
||||
}
|
||||
|
||||
if (!strcmp((char *)ptr, "PAL")) {
|
||||
memcpy(palScreen[idx], ptr + 4, 256*3);
|
||||
gfxModuleData_setPal256(palScreen[idx]);
|
||||
} else {
|
||||
int mode = ptr2[1];
|
||||
ptr2 += 2;
|
||||
// read palette
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case 4: { // color on 3 bit
|
||||
uint16 oldPalette[32];
|
||||
|
||||
memcpy(oldPalette, ptr2, 0x20);
|
||||
ptr2 += 0x20;
|
||||
flipGen(oldPalette, 0x20);
|
||||
|
||||
for (unsigned long int i = 0; i < 32; i++) {
|
||||
gfxModuleData_convertOldPalColor(oldPalette[i], &palScreen[idx][i*3]);
|
||||
}
|
||||
|
||||
// duplicate the palette
|
||||
for (unsigned long int i = 1; i < 8; i++) {
|
||||
memcpy(&palScreen[idx][32*i*3], &palScreen[idx][0], 32*3);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 5: { // color on 4 bit
|
||||
for (unsigned long int i = 0; i < 32; i++) {
|
||||
uint8* inPtr = ptr2 + i * 2;
|
||||
uint8* outPtr = palScreen[idx] + i * 3;
|
||||
|
||||
outPtr[2] = ((inPtr[1]) & 0x0F) * 17;
|
||||
outPtr[1] = (((inPtr[1]) & 0xF0) >> 4) * 17;
|
||||
outPtr[0] = ((inPtr[0]) & 0x0F) * 17;
|
||||
}
|
||||
ptr2 += 2 * 32;
|
||||
|
||||
// duplicate the palette
|
||||
for (unsigned long int i = 1; i < 8; i++) {
|
||||
memcpy(&palScreen[idx][32*i*3], &palScreen[idx][0], 32*3);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
memcpy(palScreen[idx], ptr2, 256*3);
|
||||
ptr2 += 256 * 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
gfxModuleData_setPal256(palScreen[idx]);
|
||||
|
||||
// read image data
|
||||
gfxModuleData_gfxClearFrameBuffer(backgroundScreens[idx]);
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case 4:
|
||||
convertGfxFromMode4(ptr2, 320, 200, backgroundScreens[idx]);
|
||||
ptr2 += 32000;
|
||||
break;
|
||||
case 5:
|
||||
convertGfxFromMode5(ptr2, 320, 200, backgroundScreens[idx]);
|
||||
break;
|
||||
case 8:
|
||||
memcpy(backgroundScreens[idx], ptr2, 320 * 200);
|
||||
ptr2 += 320 * 200;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
loadMEN(&ptr2);
|
||||
loadCVT(&ptr2);
|
||||
}
|
||||
|
||||
MemFree(ptrToFree);
|
||||
|
||||
// NOTE: the following is really meant to compare pointers and not the actual
|
||||
// strings. See r48092 and r48094.
|
||||
if (name != backgroundTable[idx].name) {
|
||||
if (strlen(name) >= sizeof(backgroundTable[idx].name))
|
||||
warning("background name length exceeded allowable maximum");
|
||||
|
||||
Common::strlcpy(backgroundTable[idx].name, name, sizeof(backgroundTable[idx].name));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
42
engines/cruise/background.h
Normal file
42
engines/cruise/background.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 CRUISE_BACKGROUND_H
|
||||
#define CRUISE_BACKGROUND_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct backgroundTableStruct {
|
||||
char name[16];
|
||||
char extension[6];
|
||||
};
|
||||
|
||||
extern short int cvtPalette[0x20];
|
||||
extern int CVTLoaded;
|
||||
extern uint8 *backgroundScreens[8];
|
||||
extern bool backgroundChanged[8];
|
||||
extern backgroundTableStruct backgroundTable[8];
|
||||
|
||||
int loadBackground(const char *name, int idx);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
355
engines/cruise/backgroundIncrust.cpp
Normal file
355
engines/cruise/backgroundIncrust.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
#include "cruise/cruise.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
static const char *endTexts[] = {
|
||||
"The End", // English
|
||||
"Fin", // French
|
||||
"Ende", // German
|
||||
"El Fin", // Spanish
|
||||
"Fine" // Italian
|
||||
};
|
||||
|
||||
enum EndTextIndex {
|
||||
kEnglish = 0,
|
||||
kFrench = 1,
|
||||
kGerman = 2,
|
||||
kSpanish = 3,
|
||||
kItalian = 4
|
||||
};
|
||||
|
||||
backgroundIncrustStruct backgroundIncrustHead;
|
||||
|
||||
void resetBackgroundIncrustList(backgroundIncrustStruct *pHead) {
|
||||
pHead->next = nullptr;
|
||||
pHead->prev = nullptr;
|
||||
}
|
||||
|
||||
// blit background to another one
|
||||
void addBackgroundIncrustSub1(int fileIdx, int X, int Y, char *ptr2, int16 scale, char *destBuffer, char *dataPtr) {
|
||||
assert((dataPtr != nullptr) && (*dataPtr != 0));
|
||||
|
||||
buildPolyModel(X, Y, scale, ptr2, destBuffer, dataPtr);
|
||||
}
|
||||
|
||||
void backupBackground(backgroundIncrustStruct *pIncrust, int X, int Y, int width, int height, uint8* pBackground) {
|
||||
pIncrust->saveWidth = width;
|
||||
pIncrust->saveHeight = height;
|
||||
pIncrust->saveSize = width * height;
|
||||
pIncrust->savedX = X;
|
||||
pIncrust->savedY = Y;
|
||||
|
||||
pIncrust->ptr = (uint8 *)MemAlloc(width * height);
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int xp = j + X;
|
||||
int yp = i + Y;
|
||||
|
||||
pIncrust->ptr[i * width + j] = ((xp < 0) || (yp < 0) || (xp >= 320) || (yp >= 200)) ?
|
||||
0 : pBackground[yp * 320 + xp];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void restoreBackground(backgroundIncrustStruct *pIncrust) {
|
||||
if (!pIncrust)
|
||||
return;
|
||||
if (pIncrust->type != 1)
|
||||
return;
|
||||
if (pIncrust->ptr == nullptr)
|
||||
return;
|
||||
|
||||
uint8* pBackground = backgroundScreens[pIncrust->backgroundIdx];
|
||||
if (pBackground == nullptr)
|
||||
return;
|
||||
|
||||
backgroundChanged[pIncrust->backgroundIdx] = true;
|
||||
|
||||
int X = pIncrust->savedX;
|
||||
int Y = pIncrust->savedY;
|
||||
int width = pIncrust->saveWidth;
|
||||
int height = pIncrust->saveHeight;
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int xp = j + X;
|
||||
int yp = i + Y;
|
||||
|
||||
if ((xp >= 0) && (yp >= 0) && (xp < 320) && (yp < 200))
|
||||
pBackground[yp * 320 + xp] = pIncrust->ptr[i * width + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backgroundIncrustStruct *addBackgroundIncrust(int16 overlayIdx, int16 objectIdx, backgroundIncrustStruct *pHead, int16 scriptNumber, int16 scriptOverlay, int16 backgroundIdx, int16 saveBuffer) {
|
||||
objectParamsQuery params;
|
||||
getMultipleObjectParam(overlayIdx, objectIdx, ¶ms);
|
||||
|
||||
uint8 *ptr = filesDatabase[params.fileIdx].subData.ptr;
|
||||
|
||||
// Don't process any further if not a sprite or polygon
|
||||
if (!ptr)
|
||||
return nullptr;
|
||||
|
||||
if ((filesDatabase[params.fileIdx].subData.resourceType != OBJ_TYPE_SPRITE) &&
|
||||
(filesDatabase[params.fileIdx].subData.resourceType != OBJ_TYPE_POLY))
|
||||
return nullptr;
|
||||
|
||||
uint8 *backgroundPtr = backgroundScreens[backgroundIdx];
|
||||
assert(backgroundPtr != nullptr);
|
||||
|
||||
backgroundChanged[backgroundIdx] = true;
|
||||
backgroundIncrustStruct *currentHead = pHead;
|
||||
backgroundIncrustStruct *currentHead2 = currentHead->next;
|
||||
|
||||
while (currentHead2) {
|
||||
currentHead = currentHead2;
|
||||
currentHead2 = currentHead->next;
|
||||
}
|
||||
|
||||
backgroundIncrustStruct *newElement = (backgroundIncrustStruct *)mallocAndZero(sizeof(backgroundIncrustStruct));
|
||||
|
||||
if (!newElement)
|
||||
return nullptr;
|
||||
|
||||
newElement->next = currentHead->next;
|
||||
currentHead->next = newElement;
|
||||
|
||||
if (!currentHead2)
|
||||
currentHead2 = pHead;
|
||||
|
||||
newElement->prev = currentHead2->prev;
|
||||
currentHead2->prev = newElement;
|
||||
newElement->objectIdx = objectIdx;
|
||||
newElement->type = saveBuffer;
|
||||
newElement->backgroundIdx = backgroundIdx;
|
||||
newElement->overlayIdx = overlayIdx;
|
||||
newElement->scriptNumber = scriptNumber;
|
||||
newElement->scriptOverlayIdx = scriptOverlay;
|
||||
newElement->X = params.X;
|
||||
newElement->Y = params.Y;
|
||||
newElement->scale = params.scale;
|
||||
newElement->frame = params.fileIdx;
|
||||
newElement->spriteId = filesDatabase[params.fileIdx].subData.index;
|
||||
newElement->ptr = nullptr;
|
||||
Common::strcpy_s(newElement->name, filesDatabase[params.fileIdx].subData.name);
|
||||
|
||||
if (_vm->getLanguage() != Common::RU_RUS && !strcmp(newElement->name, "FIN14.SET")) { // "The End" (nothing for Russian version)
|
||||
const char *text;
|
||||
|
||||
switch (_vm->getLanguage()) {
|
||||
case Common::EN_GRB:
|
||||
case Common::EN_ANY:
|
||||
text = endTexts[kEnglish];
|
||||
break;
|
||||
case Common::FR_FRA:
|
||||
text = endTexts[kFrench];
|
||||
break;
|
||||
case Common::DE_DEU:
|
||||
text = endTexts[kGerman];
|
||||
break;
|
||||
case Common::ES_ESP:
|
||||
text = endTexts[kSpanish];
|
||||
break;
|
||||
case Common::IT_ITA:
|
||||
text = endTexts[kItalian];
|
||||
break;
|
||||
default:
|
||||
text = endTexts[kEnglish];
|
||||
}
|
||||
|
||||
_vm->sayText(text, Common::TextToSpeechManager::QUEUE);
|
||||
} else if (!strcmp(newElement->name, "CFACSP02.SET")) { // Title
|
||||
if (_vm->getLanguage() == Common::FR_FRA) {
|
||||
_vm->sayText("Croisi\212re pour un Cadavre", Common::TextToSpeechManager::QUEUE);
|
||||
} else if (_vm->getLanguage() == Common::RU_RUS) {
|
||||
// "Круиз для мертвеца"
|
||||
_vm->sayText("\x8a\xe0\x93\xa8\xa7 \xa4\xab\xef \xac\xa5\xe0\xe2\xa2\xa5\xe6\xa0", Common::TextToSpeechManager::QUEUE);
|
||||
} else {
|
||||
_vm->sayText("Cruise for a Corpse", Common::TextToSpeechManager::QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (filesDatabase[params.fileIdx].subData.resourceType == OBJ_TYPE_SPRITE) {
|
||||
// sprite
|
||||
int width = filesDatabase[params.fileIdx].width;
|
||||
int height = filesDatabase[params.fileIdx].height;
|
||||
if (saveBuffer == 1)
|
||||
backupBackground(newElement, newElement->X, newElement->Y, width, height, backgroundPtr);
|
||||
|
||||
drawSprite(width, height, nullptr, filesDatabase[params.fileIdx].subData.ptr, newElement->Y,
|
||||
newElement->X, backgroundPtr, filesDatabase[params.fileIdx].subData.ptrMask);
|
||||
} else {
|
||||
// poly
|
||||
if (saveBuffer == 1) {
|
||||
int newX;
|
||||
int newY;
|
||||
int newScale;
|
||||
char *newFrame;
|
||||
|
||||
int sizeTable[4]; // 0 = left, 1 = right, 2 = bottom, 3 = top
|
||||
|
||||
// this function checks if the dataPtr is not 0, else it retrieves the data for X, Y, scale and DataPtr again (OLD: mainDrawSub1Sub1)
|
||||
flipPoly(params.fileIdx, (int16 *)filesDatabase[params.fileIdx].subData.ptr, params.scale, &newFrame, newElement->X, newElement->Y, &newX, &newY, &newScale);
|
||||
|
||||
// this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2)
|
||||
getPolySize(newX, newY, newScale, sizeTable, (unsigned char*)newFrame);
|
||||
|
||||
int width = (sizeTable[1] + 2) - (sizeTable[0] - 2) + 1;
|
||||
int height = sizeTable[3] - sizeTable[2] + 1;
|
||||
|
||||
backupBackground(newElement, sizeTable[0] - 2, sizeTable[2], width, height, backgroundPtr);
|
||||
}
|
||||
|
||||
addBackgroundIncrustSub1(params.fileIdx, newElement->X, newElement->Y, nullptr, params.scale, (char *)backgroundPtr, (char *)filesDatabase[params.fileIdx].subData.ptr);
|
||||
}
|
||||
|
||||
return newElement;
|
||||
}
|
||||
|
||||
void regenerateBackgroundIncrust(backgroundIncrustStruct *pHead) {
|
||||
lastAni[0] = 0;
|
||||
backgroundIncrustStruct *pl = pHead->next;
|
||||
|
||||
while (pl) {
|
||||
backgroundIncrustStruct* pl2 = pl->next;
|
||||
|
||||
int frame = pl->frame;
|
||||
if (frame < 0)
|
||||
error("regenerateBackgroundIncrust() : Unexpected use of negative frame index");
|
||||
|
||||
if ((filesDatabase[frame].subData.ptr == nullptr) || (strcmp(pl->name, filesDatabase[frame].subData.name))) {
|
||||
frame = NUM_FILE_ENTRIES - 1;
|
||||
if (loadFile(pl->name, frame, pl->spriteId) < 0)
|
||||
frame = -1;
|
||||
}
|
||||
|
||||
if (frame >= 0) {
|
||||
if (filesDatabase[frame].subData.resourceType == OBJ_TYPE_SPRITE) {
|
||||
// Sprite
|
||||
int width = filesDatabase[frame].width;
|
||||
int height = filesDatabase[frame].height;
|
||||
|
||||
drawSprite(width, height, nullptr, filesDatabase[frame].subData.ptr, pl->Y, pl->X, backgroundScreens[pl->backgroundIdx], filesDatabase[frame].subData.ptrMask);
|
||||
} else {
|
||||
// Poly
|
||||
addBackgroundIncrustSub1(frame, pl->X, pl->Y, nullptr, pl->scale, (char *)backgroundScreens[pl->backgroundIdx], (char *)filesDatabase[frame].subData.ptr);
|
||||
}
|
||||
|
||||
backgroundChanged[pl->backgroundIdx] = true;
|
||||
}
|
||||
|
||||
pl = pl2;
|
||||
}
|
||||
|
||||
lastAni[0] = 0;
|
||||
}
|
||||
|
||||
void freeBackgroundIncrustList(backgroundIncrustStruct *pHead) {
|
||||
backgroundIncrustStruct *pCurrent = pHead->next;
|
||||
|
||||
while (pCurrent) {
|
||||
backgroundIncrustStruct *pNext = pCurrent->next;
|
||||
|
||||
if (pCurrent->ptr)
|
||||
MemFree(pCurrent->ptr);
|
||||
|
||||
MemFree(pCurrent);
|
||||
pCurrent = pNext;
|
||||
}
|
||||
|
||||
resetBackgroundIncrustList(pHead);
|
||||
}
|
||||
|
||||
void removeBackgroundIncrust(int overlay, int idx, backgroundIncrustStruct * pHead) {
|
||||
objectParamsQuery params;
|
||||
|
||||
getMultipleObjectParam(overlay, idx, ¶ms);
|
||||
|
||||
int x = params.X;
|
||||
int y = params.Y;
|
||||
|
||||
backgroundIncrustStruct *pCurrent = pHead->next;
|
||||
while (pCurrent) {
|
||||
if ((pCurrent->overlayIdx == overlay || overlay == -1) && (pCurrent->objectIdx == idx || idx == -1) && (pCurrent->X == x) && (pCurrent->Y == y))
|
||||
pCurrent->type = -1;
|
||||
|
||||
pCurrent = pCurrent->next;
|
||||
}
|
||||
|
||||
backgroundIncrustStruct *pCurrentHead = pHead;
|
||||
pCurrent = pHead->next;
|
||||
|
||||
while (pCurrent) {
|
||||
if (pCurrent->type == -1) {
|
||||
backgroundIncrustStruct *pNext = pCurrent->next;
|
||||
backgroundIncrustStruct *bx = pCurrentHead;
|
||||
|
||||
bx->next = pNext;
|
||||
backgroundIncrustStruct *cx = pNext;
|
||||
|
||||
if (!pNext)
|
||||
cx = pHead;
|
||||
|
||||
bx = cx;
|
||||
bx->prev = pCurrent->next;
|
||||
|
||||
if (pCurrent->ptr)
|
||||
MemFree(pCurrent->ptr);
|
||||
|
||||
MemFree(pCurrent);
|
||||
pCurrent = pNext;
|
||||
} else {
|
||||
pCurrentHead = pCurrent;
|
||||
pCurrent = pCurrent->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unmergeBackgroundIncrust(backgroundIncrustStruct * pHead, int ovl, int idx) {
|
||||
objectParamsQuery params;
|
||||
getMultipleObjectParam(ovl, idx, ¶ms);
|
||||
|
||||
int x = params.X;
|
||||
int y = params.Y;
|
||||
|
||||
backgroundIncrustStruct *pl = pHead;
|
||||
backgroundIncrustStruct *pl2 = pl;
|
||||
pl = pl2->next;
|
||||
|
||||
while (pl) {
|
||||
pl2 = pl;
|
||||
if ((pl->overlayIdx == ovl) || (ovl == -1)) {
|
||||
if ((pl->objectIdx == idx) || (idx == -1)) {
|
||||
if ((pl->X == x) && (pl->Y == y))
|
||||
restoreBackground(pl);
|
||||
}
|
||||
}
|
||||
|
||||
pl = pl2->next;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
62
engines/cruise/backgroundIncrust.h
Normal file
62
engines/cruise/backgroundIncrust.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* 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 CRUISE_BACKGROUNDINCRUST_H
|
||||
#define CRUISE_BACKGROUNDINCRUST_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct backgroundIncrustStruct {
|
||||
struct backgroundIncrustStruct *next;
|
||||
struct backgroundIncrustStruct *prev;
|
||||
|
||||
uint16 objectIdx;
|
||||
int16 type;
|
||||
uint16 overlayIdx;
|
||||
int16 X;
|
||||
int16 Y;
|
||||
uint16 frame;
|
||||
uint16 scale;
|
||||
uint16 backgroundIdx;
|
||||
uint16 scriptNumber;
|
||||
uint16 scriptOverlayIdx;
|
||||
uint8 *ptr;
|
||||
int16 saveWidth;
|
||||
int16 saveHeight;
|
||||
uint16 saveSize;
|
||||
int16 savedX;
|
||||
int16 savedY;
|
||||
char name[13];
|
||||
uint16 spriteId;
|
||||
};
|
||||
|
||||
extern backgroundIncrustStruct backgroundIncrustHead;
|
||||
|
||||
void resetBackgroundIncrustList(backgroundIncrustStruct * pHead);
|
||||
backgroundIncrustStruct *addBackgroundIncrust(int16 overlayIdx, int16 param2, backgroundIncrustStruct * pHead, int16 scriptNumber, int16 scriptOverlay, int16 backgroundIdx, int16 param4);
|
||||
void regenerateBackgroundIncrust(backgroundIncrustStruct * pHead);
|
||||
void freeBackgroundIncrustList(backgroundIncrustStruct * pHead);
|
||||
void removeBackgroundIncrust(int overlay, int idx, backgroundIncrustStruct * pHead);
|
||||
void unmergeBackgroundIncrust(backgroundIncrustStruct * pHead, int ovl, int idx);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
349
engines/cruise/cell.cpp
Normal file
349
engines/cruise/cell.cpp
Normal file
@@ -0,0 +1,349 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
#include "common/file.h"
|
||||
#include "cruise/cell.h"
|
||||
#include "cruise/cruise.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
cellStruct cellHead;
|
||||
|
||||
void resetPtr(cellStruct *ptr) {
|
||||
ptr->next = nullptr;
|
||||
ptr->prev = nullptr;
|
||||
}
|
||||
|
||||
void freeMessageList(cellStruct *objPtr) {
|
||||
/* if (objPtr) {
|
||||
if (objPtr->next)
|
||||
MemFree(objPtr->next);
|
||||
|
||||
MemFree(objPtr);
|
||||
} */
|
||||
}
|
||||
|
||||
cellStruct *addCell(cellStruct *pHead, int16 overlayIdx, int16 objIdx, int16 type, int16 backgroundPlane, int16 scriptOverlay, int16 scriptNumber, int16 scriptType) {
|
||||
int16 var;
|
||||
|
||||
cellStruct *newElement;
|
||||
cellStruct *currentHead = pHead;
|
||||
cellStruct *currentHead2;
|
||||
cellStruct *currentHead3;
|
||||
|
||||
if (getSingleObjectParam(overlayIdx, objIdx, 2, &var) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
currentHead3 = currentHead;
|
||||
currentHead2 = currentHead->next;
|
||||
|
||||
while (currentHead2 && (currentHead2->type != 3)) {
|
||||
|
||||
if (currentHead2->type != 5) {
|
||||
int16 lvar2;
|
||||
|
||||
if (getSingleObjectParam(currentHead2->overlay, currentHead2->idx, 2, &lvar2) >= 0 && lvar2 >= var)
|
||||
break;
|
||||
}
|
||||
|
||||
currentHead3 = currentHead2;
|
||||
currentHead2 = currentHead2->next;
|
||||
}
|
||||
|
||||
if (currentHead2) {
|
||||
if ((currentHead2->overlay == overlayIdx) &&
|
||||
(currentHead2->backgroundPlane == backgroundPlane) &&
|
||||
(currentHead2->idx == objIdx) &&
|
||||
(currentHead2->type == type))
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
currentHead = currentHead2;
|
||||
|
||||
newElement = (cellStruct *) mallocAndZero(sizeof(cellStruct));
|
||||
|
||||
if (!newElement)
|
||||
return nullptr;
|
||||
|
||||
newElement->next = currentHead3->next;
|
||||
currentHead3->next = newElement;
|
||||
|
||||
newElement->idx = objIdx;
|
||||
newElement->type = type;
|
||||
newElement->backgroundPlane = backgroundPlane;
|
||||
newElement->overlay = overlayIdx;
|
||||
newElement->freeze = 0;
|
||||
newElement->parent = scriptNumber;
|
||||
newElement->parentOverlay = scriptOverlay;
|
||||
newElement->gfxPtr = nullptr;
|
||||
newElement->followObjectIdx = objIdx;
|
||||
newElement->followObjectOverlayIdx = overlayIdx;
|
||||
newElement->parentType = scriptType;
|
||||
|
||||
newElement->animStart = 0;
|
||||
newElement->animEnd = 0;
|
||||
newElement->animWait = 0;
|
||||
newElement->animSignal = 0;
|
||||
newElement->animCounter = 0;
|
||||
newElement->animType = 0;
|
||||
newElement->animStep = 0;
|
||||
newElement->animLoop = 0;
|
||||
|
||||
if (currentHead) {
|
||||
newElement->prev = currentHead->prev;
|
||||
currentHead->prev = newElement;
|
||||
} else {
|
||||
newElement->prev = pHead->prev;
|
||||
pHead->prev = newElement;
|
||||
}
|
||||
|
||||
return newElement;
|
||||
}
|
||||
|
||||
void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x, int y, int width, int16 color, int backgroundPlane, int parentOvl, int parentIdx) {
|
||||
|
||||
const char *ax;
|
||||
cellStruct *savePObject = pObject;
|
||||
cellStruct *cx;
|
||||
|
||||
cellStruct *pNewElement;
|
||||
cellStruct *si = pObject->next;
|
||||
|
||||
while (si) {
|
||||
pObject = si;
|
||||
si = si->next;
|
||||
}
|
||||
|
||||
pNewElement = (cellStruct *) MemAlloc(sizeof(cellStruct));
|
||||
memset(pNewElement, 0, sizeof(cellStruct));
|
||||
|
||||
pNewElement->next = pObject->next;
|
||||
pObject->next = pNewElement;
|
||||
|
||||
pNewElement->idx = messageIdx;
|
||||
pNewElement->type = OBJ_TYPE_MESSAGE;
|
||||
pNewElement->backgroundPlane = backgroundPlane;
|
||||
pNewElement->overlay = overlayIdx;
|
||||
pNewElement->x = x;
|
||||
pNewElement->field_C = y;
|
||||
pNewElement->spriteIdx = width;
|
||||
pNewElement->color = color;
|
||||
pNewElement->freeze = 0;
|
||||
pNewElement->parent = parentIdx;
|
||||
pNewElement->parentOverlay = parentOvl;
|
||||
pNewElement->gfxPtr = nullptr;
|
||||
|
||||
cx = savePObject;
|
||||
|
||||
pNewElement->prev = cx->prev;
|
||||
cx->prev = pNewElement;
|
||||
|
||||
ax = getText(messageIdx, overlayIdx);
|
||||
Common::String ttsMessage;
|
||||
|
||||
if (ax) {
|
||||
pNewElement->gfxPtr = renderText(width, ax);
|
||||
ttsMessage = ax;
|
||||
ttsMessage.replace('|', '\n');
|
||||
}
|
||||
|
||||
if (!strcmp(overlayTable[overlayIdx].overlayName, "XX2")) {
|
||||
// The English DOS and Russian versions automatically skip past the copy protection screen, so don't voice
|
||||
// any of its text
|
||||
if ((_vm->getLanguage() != Common::EN_ANY && _vm->getLanguage() != Common::RU_RUS && _vm->getLanguage() != Common::EN_GRB) ||
|
||||
_vm->getPlatform() != Common::kPlatformDOS) {
|
||||
// Don't voice the "OK" button (index 32) here
|
||||
if (messageIdx != 32) {
|
||||
_vm->sayText(ttsMessage, Common::TextToSpeechManager::QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
// WORKAROUND: This is needed for the new dirty rect handling so as to properly refresh the screen
|
||||
// when the copy protection screen is being shown
|
||||
if (messageIdx == 0)
|
||||
backgroundChanged[0] = true;
|
||||
} else {
|
||||
// Sometimes this text shows up on screen later, so queue it up to be spoken
|
||||
_vm->_toSpeak = ttsMessage;
|
||||
_vm->_previousSaid.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void removeCell(cellStruct *objPtr, int ovlNumber, int objectIdx, int objType, int backgroundPlane) {
|
||||
cellStruct *currentObj = objPtr->next;
|
||||
cellStruct *previous;
|
||||
|
||||
while (currentObj) {
|
||||
if (((currentObj->overlay == ovlNumber) || (ovlNumber == -1)) &&
|
||||
((currentObj->idx == objectIdx) || (objectIdx == -1)) &&
|
||||
((currentObj->type == objType) || (objType == -1)) &&
|
||||
((currentObj->backgroundPlane == backgroundPlane) || (backgroundPlane == -1))) {
|
||||
currentObj->type = -1;
|
||||
}
|
||||
|
||||
currentObj = currentObj->next;
|
||||
}
|
||||
|
||||
previous = objPtr;
|
||||
currentObj = objPtr->next;
|
||||
|
||||
while (currentObj) {
|
||||
cellStruct *si;
|
||||
|
||||
si = currentObj;
|
||||
|
||||
if (si->type == -1) {
|
||||
cellStruct *dx;
|
||||
previous->next = si->next;
|
||||
|
||||
dx = si->next;
|
||||
|
||||
if (!si->next) {
|
||||
dx = objPtr;
|
||||
}
|
||||
|
||||
dx->prev = si->prev;
|
||||
|
||||
// Free the entry
|
||||
if (si->gfxPtr)
|
||||
freeGfx(si->gfxPtr);
|
||||
MemFree(si);
|
||||
|
||||
currentObj = dx;
|
||||
} else {
|
||||
currentObj = si->next;
|
||||
previous = si;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void linkCell(cellStruct *pHead, int ovl, int obj, int type, int ovl2, int obj2) {
|
||||
while (pHead) {
|
||||
if ((pHead->overlay == ovl) || (ovl == -1)) {
|
||||
if ((pHead->idx == obj) || (obj == -1)) {
|
||||
if ((pHead->type == type) || (type == -1)) {
|
||||
pHead->followObjectIdx = obj2;
|
||||
pHead->followObjectOverlayIdx = ovl2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pHead = pHead->next;
|
||||
}
|
||||
}
|
||||
|
||||
void freezeCell(cellStruct * pObject, int overlayIdx, int objIdx, int objType, int backgroundPlane, int oldFreeze, int newFreeze) {
|
||||
while (pObject) {
|
||||
if ((pObject->overlay == overlayIdx) || (overlayIdx == -1)) {
|
||||
if ((pObject->idx == objIdx) || (objIdx == -1)) {
|
||||
if ((pObject->type == objType) || (objType == -1)) {
|
||||
if ((pObject->backgroundPlane == backgroundPlane) || (backgroundPlane == -1)) {
|
||||
if ((pObject->freeze == oldFreeze) || (oldFreeze == -1)) {
|
||||
pObject->freeze = newFreeze;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pObject = pObject->next;
|
||||
}
|
||||
}
|
||||
|
||||
void sortCells(int16 ovlIdx, int16 ovjIdx, cellStruct *objPtr) {
|
||||
cellStruct *pl, *pl2, *pl3, *pl4, *plz, *pllast;
|
||||
cellStruct prov;
|
||||
int16 newz, objz, sobjz;
|
||||
|
||||
pl4 = nullptr;
|
||||
|
||||
getSingleObjectParam(ovlIdx, ovjIdx, 2, &sobjz);
|
||||
pl = objPtr;
|
||||
prov.next = nullptr;
|
||||
prov.prev = nullptr;
|
||||
|
||||
pl2 = pl->next;
|
||||
pllast = nullptr;
|
||||
plz = objPtr;
|
||||
|
||||
while (pl2) {
|
||||
pl3 = pl2->next;
|
||||
if ((pl2->overlay == ovlIdx) && (pl2->idx == ovjIdx)) {// found
|
||||
pl->next = pl3;
|
||||
|
||||
if (pl3) {
|
||||
pl3->prev = pl2->prev;
|
||||
} else {
|
||||
objPtr->prev = pl2->prev;
|
||||
}
|
||||
|
||||
pl4 = prov.next;
|
||||
|
||||
if (pl4) {
|
||||
pl4->prev = pl2;
|
||||
} else {
|
||||
prov.prev = pl2;
|
||||
}
|
||||
|
||||
pl2->prev = nullptr;
|
||||
pl2->next = prov.next;
|
||||
prov.next = pl2;
|
||||
|
||||
if (pllast == nullptr) {
|
||||
pllast = pl2;
|
||||
}
|
||||
} else {
|
||||
if (pl2->type == 5) {
|
||||
newz = 32000;
|
||||
} else {
|
||||
getSingleObjectParam(pl2->overlay, pl2->idx, 2, &objz);
|
||||
newz = objz;
|
||||
}
|
||||
|
||||
if (newz < sobjz) {
|
||||
plz = pl2;
|
||||
}
|
||||
|
||||
pl = pl->next;
|
||||
}
|
||||
|
||||
pl2 = pl3;
|
||||
}
|
||||
|
||||
if (pllast) {
|
||||
pl2 = prov.next;
|
||||
pl4 = plz->next;
|
||||
plz->next = pl2;
|
||||
pllast->next = pl4;
|
||||
|
||||
if (plz != objPtr)
|
||||
pl2->prev = plz;
|
||||
if (!pl4)
|
||||
objPtr->prev = pllast;
|
||||
else
|
||||
pl4->prev = pllast;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
74
engines/cruise/cell.h
Normal file
74
engines/cruise/cell.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 CRUISE_CELL_H
|
||||
#define CRUISE_CELL_H
|
||||
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct gfxEntryStruct;
|
||||
|
||||
struct cellStruct {
|
||||
struct cellStruct *next;
|
||||
struct cellStruct *prev;
|
||||
int16 idx;
|
||||
int16 type;
|
||||
int16 overlay;
|
||||
int16 x;
|
||||
int16 field_C;
|
||||
int16 spriteIdx;
|
||||
int16 color;
|
||||
int16 backgroundPlane;
|
||||
int16 freeze;
|
||||
int16 parent;
|
||||
int16 parentOverlay;
|
||||
int16 parentType;
|
||||
int16 followObjectOverlayIdx;
|
||||
int16 followObjectIdx;
|
||||
int16 animStart;
|
||||
int16 animEnd;
|
||||
int16 animWait;
|
||||
int16 animStep;
|
||||
int16 animChange;
|
||||
int16 animType;
|
||||
int16 animSignal;
|
||||
int16 animCounter;
|
||||
int16 animLoop;
|
||||
gfxEntryStruct *gfxPtr;
|
||||
};
|
||||
|
||||
extern cellStruct cellHead;
|
||||
|
||||
void resetPtr(cellStruct * ptr);
|
||||
cellStruct *addCell(cellStruct *pHead, int16 overlayIdx, int16 objIdx, int16 type, int16 backgroundPlane, int16 scriptOverlay, int16 scriptNumber, int16 scriptType);
|
||||
void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x, int y, int width, int16 color, int backgroundPlane, int parentOvl, int parentIdx);
|
||||
void removeCell(cellStruct *objPtr, int ovlNumber, int objectIdx, int objType, int backgroundPlane);
|
||||
void freezeCell(cellStruct * pObject, int overlayIdx, int objIdx, int objType, int backgroundPlane, int oldFreeze, int newFreeze);
|
||||
void sortCells(int16 param1, int16 param2, cellStruct *objPtr);
|
||||
void linkCell(cellStruct *pHead, int ovl, int obj, int type, int ovl2, int obj2);
|
||||
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
3
engines/cruise/configure.engine
Normal file
3
engines/cruise/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 cruise "Cinematique evo 2" yes
|
||||
4
engines/cruise/credits.pl
Normal file
4
engines/cruise/credits.pl
Normal file
@@ -0,0 +1,4 @@
|
||||
begin_section("CruisE");
|
||||
add_person("Paul Gilbert", "dreammaster", "");
|
||||
add_person("Vincent Hamm", "yaz0r", "(retired)");
|
||||
end_section();
|
||||
279
engines/cruise/cruise.cpp
Normal file
279
engines/cruise/cruise.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/* 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/debug-channels.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/font.h"
|
||||
#include "cruise/gfxModule.h"
|
||||
#include "cruise/staticres.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
//SoundDriver *g_soundDriver;
|
||||
//SfxPlayer *g_sfxPlayer;
|
||||
|
||||
CruiseEngine *_vm;
|
||||
|
||||
CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc)
|
||||
: Engine(syst), _gameDescription(gameDesc), _rnd("cruise") {
|
||||
|
||||
_vm = this;
|
||||
setDebugger(new Debugger());
|
||||
_sound = new PCSound(_mixer, this);
|
||||
|
||||
PCFadeFlag = false;
|
||||
_preLoad = false;
|
||||
_savedCursor = CURSOR_NOMOUSE;
|
||||
_lastTick = 0;
|
||||
_gameSpeed = GAME_FRAME_DELAY_1;
|
||||
_speedFlag = false;
|
||||
_polyStructs = nullptr;
|
||||
_polyStruct = nullptr;
|
||||
|
||||
_mouseButtonDown = false;
|
||||
_menuJustOpened = false;
|
||||
|
||||
// Setup mixer
|
||||
syncSoundSettings();
|
||||
}
|
||||
|
||||
extern void listMemory();
|
||||
|
||||
CruiseEngine::~CruiseEngine() {
|
||||
delete _sound;
|
||||
|
||||
freeSystem();
|
||||
|
||||
if (gDebugLevel > 0)
|
||||
MemoryList();
|
||||
}
|
||||
|
||||
bool CruiseEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime);
|
||||
}
|
||||
|
||||
Common::Error CruiseEngine::run() {
|
||||
// Initialize backend
|
||||
initGraphics(320, 200);
|
||||
|
||||
if (!loadLanguageStrings()) {
|
||||
error("Could not setup language data for your version");
|
||||
return Common::kUnknownError; // for compilers that don't support NORETURN
|
||||
}
|
||||
|
||||
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
|
||||
if (ttsMan != nullptr) {
|
||||
ttsMan->enable(ConfMan.getBool("tts_enabled"));
|
||||
ttsMan->setLanguage(ConfMan.get("language"));
|
||||
|
||||
if (getLanguage() == Common::FR_FRA || getLanguage() == Common::IT_ITA) {
|
||||
_ttsTextEncoding = Common::CodePage::kWindows1252;
|
||||
} else if (getLanguage() == Common::RU_RUS) {
|
||||
_ttsTextEncoding = Common::CodePage::kDos866;
|
||||
} else {
|
||||
_ttsTextEncoding = Common::CodePage::kDos850;
|
||||
}
|
||||
}
|
||||
|
||||
initialize();
|
||||
|
||||
Cruise::changeCursor(Cruise::CURSOR_NORMAL);
|
||||
CursorMan.showMouse(true);
|
||||
|
||||
mainLoop();
|
||||
|
||||
deinitialize();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void CruiseEngine::initialize() {
|
||||
// video init stuff
|
||||
initSystem();
|
||||
gfxModuleData_Init();
|
||||
|
||||
// another bit of video init
|
||||
readVolCnf();
|
||||
}
|
||||
|
||||
void CruiseEngine::deinitialize() {
|
||||
_vm->_polyStructNorm.clear();
|
||||
_vm->_polyStructExp.clear();
|
||||
|
||||
// Clear any backgrounds
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (backgroundScreens[i]) {
|
||||
MemFree(backgroundScreens[i]);
|
||||
backgroundScreens[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CruiseEngine::loadLanguageStrings() {
|
||||
Common::File f;
|
||||
|
||||
// Give preference to a language file
|
||||
if (f.open("DELPHINE.LNG")) {
|
||||
char *data = (char *)MemAlloc(f.size());
|
||||
f.read(data, f.size());
|
||||
char *ptr = data;
|
||||
|
||||
for (int i = 0; i < MAX_LANGUAGE_STRINGS; ++i) {
|
||||
// Get the start of the next string
|
||||
while (*ptr != '"') ++ptr;
|
||||
const char *v = ++ptr;
|
||||
|
||||
// Find the end of the string, and replace the end '"' with a NULL
|
||||
while (*ptr != '"') ++ptr;
|
||||
*ptr++ = '\0';
|
||||
|
||||
// Add the string to the list
|
||||
_langStrings.push_back(v);
|
||||
}
|
||||
|
||||
f.close();
|
||||
MemFree(data);
|
||||
|
||||
} else {
|
||||
// Try and use one of the pre-defined language lists
|
||||
const char **p = nullptr;
|
||||
switch (getLanguage()) {
|
||||
case Common::EN_ANY:
|
||||
p = englishLanguageStrings;
|
||||
break;
|
||||
case Common::FR_FRA:
|
||||
p = frenchLanguageStrings;
|
||||
break;
|
||||
case Common::DE_DEU:
|
||||
p = germanLanguageStrings;
|
||||
break;
|
||||
case Common::IT_ITA:
|
||||
p = italianLanguageStrings;
|
||||
break;
|
||||
case Common::ES_ESP:
|
||||
p = spanishLanguageStrings;
|
||||
break;
|
||||
case Common::RU_RUS:
|
||||
p = russianLanguageStrings;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load in the located language set
|
||||
for (int i = 0; i < 13; ++i, ++p)
|
||||
_langStrings.push_back(*p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CruiseEngine::pauseEngine(bool pause) {
|
||||
if (pause) {
|
||||
_gamePauseToken = Engine::pauseEngine();
|
||||
// Draw the 'Paused' message
|
||||
drawSolidBox(64, 100, 256, 117, 0);
|
||||
drawString(10, 100, langString(ID_PAUSED), gfxModuleData.pPage00, itemColor, 300);
|
||||
gfxModuleData_flipScreen();
|
||||
|
||||
_savedCursor = currentCursor;
|
||||
changeCursor(CURSOR_NOMOUSE);
|
||||
} else {
|
||||
_gamePauseToken.clear();
|
||||
processAnimation();
|
||||
flipScreen();
|
||||
changeCursor(_savedCursor);
|
||||
|
||||
_vm->stopTextToSpeech();
|
||||
}
|
||||
|
||||
gfxModuleData_addDirtyRect(Common::Rect(64, 100, 256, 117));
|
||||
}
|
||||
|
||||
void CruiseEngine::sayText(const Common::String &text, Common::TextToSpeechManager::Action action) {
|
||||
if (text.empty() && action == Common::TextToSpeechManager::QUEUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
|
||||
// _previousSaid is used to prevent the TTS from looping when sayText is called inside a loop,
|
||||
// for example when the cursor stays on a menu item. Without it when the text ends it would speak
|
||||
// the same text again.
|
||||
// _previousSaid is cleared when appropriate to allow for repeat requests
|
||||
if (ttsMan != nullptr && ConfMan.getBool("tts_enabled") && _previousSaid != text) {
|
||||
ttsMan->say(text, action, _ttsTextEncoding);
|
||||
_previousSaid = text;
|
||||
}
|
||||
}
|
||||
|
||||
void CruiseEngine::sayQueuedText(Common::TextToSpeechManager::Action action) {
|
||||
sayText(_toSpeak, action);
|
||||
_toSpeak.clear();
|
||||
}
|
||||
|
||||
void CruiseEngine::stopTextToSpeech() {
|
||||
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
|
||||
if (ttsMan != nullptr && ConfMan.getBool("tts_enabled") && ttsMan->isSpeaking()) {
|
||||
ttsMan->stop();
|
||||
_previousSaid.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Common::Error CruiseEngine::loadGameState(int slot) {
|
||||
return loadSavegameData(slot);
|
||||
}
|
||||
|
||||
bool CruiseEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return playerMenuEnabled != 0;
|
||||
}
|
||||
|
||||
Common::Error CruiseEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
return saveSavegameData(slot, desc);
|
||||
}
|
||||
|
||||
bool CruiseEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return (playerMenuEnabled != 0) && (userEnabled != 0);
|
||||
}
|
||||
|
||||
const char *CruiseEngine::getSavegameFile(int saveGameIdx) {
|
||||
static char buffer[20];
|
||||
Common::sprintf_s(buffer, "cruise.s%02d", saveGameIdx);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void CruiseEngine::syncSoundSettings() {
|
||||
Engine::syncSoundSettings();
|
||||
|
||||
_sound->syncSounds();
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
187
engines/cruise/cruise.h
Normal file
187
engines/cruise/cruise.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/* 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 CRUISE_CRUISE_H
|
||||
#define CRUISE_CRUISE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/util.h"
|
||||
#include "common/random.h"
|
||||
#include "common/text-to-speech.h"
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/debugger.h"
|
||||
#include "cruise/sound.h"
|
||||
|
||||
/**
|
||||
* This is the namespace of the Cruise engine.
|
||||
*
|
||||
* Status of this engine: Game is completable, engine needs objectifying
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Cruise for a Corpse
|
||||
*/
|
||||
namespace Cruise {
|
||||
|
||||
#define GAME_FRAME_DELAY_1 50
|
||||
#define GAME_FRAME_DELAY_2 100
|
||||
|
||||
#define MAX_LANGUAGE_STRINGS 25
|
||||
|
||||
|
||||
|
||||
enum CRUISEAction {
|
||||
kActionNone,
|
||||
kActionFastMode,
|
||||
kActionExit,
|
||||
kActionEscape,
|
||||
kActionPause,
|
||||
kActionPlayerMenu,
|
||||
kActionInventory,
|
||||
kActionEndUserWaiting,
|
||||
kActionIncreaseGameSpeed,
|
||||
kActionDecreaseGameSpeed
|
||||
};
|
||||
|
||||
enum LangStringId { ID_PAUSED = 0, ID_INVENTORY = 5, ID_SPEAK_ABOUT = 6, ID_PLAYER_MENU = 7,
|
||||
ID_SAVE = 9, ID_LOAD = 10, ID_RESTART = 11, ID_QUIT = 12};
|
||||
|
||||
struct CRUISEGameDescription;
|
||||
|
||||
class CruiseEngine: public Engine {
|
||||
private:
|
||||
bool _preLoad;
|
||||
PCSound *_sound;
|
||||
Common::StringArray _langStrings;
|
||||
CursorType _savedCursor;
|
||||
uint32 _lastTick;
|
||||
int _gameSpeed;
|
||||
bool _speedFlag;
|
||||
PauseToken _gamePauseToken;
|
||||
|
||||
Common::CodePage _ttsTextEncoding;
|
||||
|
||||
void initialize();
|
||||
void deinitialize();
|
||||
bool loadLanguageStrings();
|
||||
void mainLoop();
|
||||
int processInput();
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
|
||||
void shutdown();
|
||||
|
||||
bool initGame();
|
||||
|
||||
public:
|
||||
CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc);
|
||||
~ CruiseEngine() override;
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
|
||||
int getGameType() const;
|
||||
const char *getGameId() const;
|
||||
uint32 getFeatures() const;
|
||||
Common::Language getLanguage() const;
|
||||
Common::Platform getPlatform() const;
|
||||
PCSound &sound() { return *_sound; }
|
||||
virtual void pauseEngine(bool pause);
|
||||
const char *langString(LangStringId langId) { return _langStrings[(int)langId].c_str(); }
|
||||
void sayText(const Common::String &text, Common::TextToSpeechManager::Action action);
|
||||
void sayQueuedText(Common::TextToSpeechManager::Action action);
|
||||
void stopTextToSpeech();
|
||||
|
||||
static const char *getSavegameFile(int saveGameIdx);
|
||||
Common::Error loadGameState(int slot) override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::String getSaveStateName(int slot) const override { return getSavegameFile(slot); }
|
||||
void syncSoundSettings() override;
|
||||
|
||||
const CRUISEGameDescription *_gameDescription;
|
||||
void initAllData();
|
||||
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
struct MemInfo {
|
||||
int32 lineNum;
|
||||
char fname[64];
|
||||
uint32 magic;
|
||||
|
||||
static uint32 const cookie = 0x41424344;
|
||||
};
|
||||
|
||||
Common::List<MemInfo *> _memList;
|
||||
|
||||
typedef Common::List<Common::Rect> RectList;
|
||||
|
||||
RectList _dirtyRects;
|
||||
RectList _priorFrameRects;
|
||||
|
||||
Common::File _currentVolumeFile;
|
||||
|
||||
Common::Array<CtStruct> _polyStructNorm;
|
||||
Common::Array<CtStruct> _polyStructExp;
|
||||
Common::Array<CtStruct> *_polyStructs;
|
||||
Common::Array<CtStruct> *_polyStruct;
|
||||
|
||||
Common::File _PAL_file;
|
||||
|
||||
Common::String _toSpeak;
|
||||
Common::String _previousSaid;
|
||||
bool _mouseButtonDown;
|
||||
bool _menuJustOpened;
|
||||
};
|
||||
|
||||
extern CruiseEngine *_vm;
|
||||
|
||||
#define BOOT_PRC_NAME "AUTO00.PRC"
|
||||
|
||||
enum {
|
||||
VAR_MOUSE_X_MODE = 253,
|
||||
VAR_MOUSE_X_POS = 249,
|
||||
VAR_MOUSE_Y_MODE = 251,
|
||||
VAR_MOUSE_Y_POS = 250
|
||||
};
|
||||
|
||||
enum {
|
||||
MOUSE_CURSOR_NORMAL = 0,
|
||||
MOUSE_CURSOR_DISK,
|
||||
MOUSE_CURSOR_CROSS
|
||||
};
|
||||
|
||||
enum {
|
||||
kCruiseDebugScript = 1,
|
||||
kCruiseDebugSound,
|
||||
};
|
||||
|
||||
enum {
|
||||
kCmpEQ = (1 << 0),
|
||||
kCmpGT = (1 << 1),
|
||||
kCmpLT = (1 << 2)
|
||||
};
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
2016
engines/cruise/cruise_main.cpp
Normal file
2016
engines/cruise/cruise_main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
122
engines/cruise/cruise_main.h
Normal file
122
engines/cruise/cruise_main.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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 CRUISE_CRUISE_MAIN_H
|
||||
#define CRUISE_CRUISE_MAIN_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "cruise/overlay.h"
|
||||
#include "cruise/object.h"
|
||||
#include "cruise/ctp.h"
|
||||
#include "cruise/actor.h"
|
||||
#include "cruise/vars.h"
|
||||
#include "cruise/font.h"
|
||||
#include "cruise/volume.h"
|
||||
#include "cruise/stack.h"
|
||||
#include "cruise/script.h"
|
||||
#include "cruise/various.h"
|
||||
#include "cruise/function.h"
|
||||
#include "cruise/saveload.h"
|
||||
#include "cruise/linker.h"
|
||||
#include "cruise/mouse.h"
|
||||
#include "cruise/gfxModule.h"
|
||||
#include "cruise/dataLoader.h"
|
||||
#include "cruise/perso.h"
|
||||
#include "cruise/menu.h"
|
||||
|
||||
#include "cruise/background.h"
|
||||
#include "cruise/backgroundIncrust.h"
|
||||
|
||||
#include "cruise/mainDraw.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
enum MouseButton {
|
||||
CRS_MB_LEFT = 1,
|
||||
CRS_MB_RIGHT = 2,
|
||||
CRS_MB_MIDDLE = 4,
|
||||
CRS_MB_BOTH = CRS_MB_LEFT | CRS_MB_RIGHT
|
||||
};
|
||||
|
||||
/*#define DUMP_SCRIPT
|
||||
#define DUMP_OBJECT*/
|
||||
|
||||
enum ResType {
|
||||
OBJ_TYPE_LINE = 0,
|
||||
OBJ_TYPE_MASK = 1,
|
||||
OBJ_TYPE_BGMASK = 2,
|
||||
OBJ_TYPE_VIRTUAL = 3,
|
||||
OBJ_TYPE_SPRITE = 4,
|
||||
OBJ_TYPE_MESSAGE = 5,
|
||||
OBJ_TYPE_SOUND = 6,
|
||||
OBJ_TYPE_FONT = 7,
|
||||
OBJ_TYPE_POLY = 8,
|
||||
OBJ_TYPE_EXIT = 9
|
||||
};
|
||||
|
||||
extern gfxEntryStruct* linkedMsgList;
|
||||
|
||||
extern int buttonDown;
|
||||
extern int selectDown;
|
||||
extern int menuDown;
|
||||
|
||||
bool delphineUnpack(byte *dst, const byte *src, int len);
|
||||
int findHighColor();
|
||||
ovlData3Struct *getOvlData3Entry(int32 scriptNumber, int32 param);
|
||||
ovlData3Struct *scriptFunc1Sub2(int32 scriptNumber, int32 param);
|
||||
void resetFileEntry(int32 entryNumber);
|
||||
uint8 *mainProc14(uint16 overlay, uint16 idx);
|
||||
void printInfoBlackBox(const char *string);
|
||||
void waitForPlayerInput();
|
||||
void loadPackedFileToMem(int fileIdx, uint8 * buffer);
|
||||
int getNumObjectsByClass(int scriptIdx, int param);
|
||||
void resetFileEntryRange(int param1, int param2);
|
||||
int getProcParam(int overlayIdx, int param2, const char * name);
|
||||
void changeScriptParamInList(int param1, int param2, scriptInstanceStruct * pScriptInstance, int newValue, int param3);
|
||||
uint8 *getDataFromData3(ovlData3Struct * ptr, int param);
|
||||
void removeExtension(const char *name, char *buffer, size_t ln);
|
||||
void resetPtr2(scriptInstanceStruct * ptr);
|
||||
void getFileExtension(const char *name, char *buffer, size_t ln);
|
||||
void *allocAndZero(int size);
|
||||
void freeStuff2();
|
||||
void mainLoop();
|
||||
void getMouseStatus(int16 *pMouseVar, int16 *pMouseX, int16 *pMouseButton, int16 *pMouseY);
|
||||
bool testMask(int x, int y, unsigned char* pData, int stride);
|
||||
menuElementSubStruct *getSelectedEntryInMenu(menuStruct *pMenu);
|
||||
void closeAllMenu();
|
||||
int removeFinishedScripts(scriptInstanceStruct *ptrHandle);
|
||||
void initBigVar3();
|
||||
void resetActorPtr(actorStruct *ptr);
|
||||
void removeAllScripts(scriptInstanceStruct *ptrHandle);
|
||||
|
||||
void MemoryList();
|
||||
void *MemoryAlloc(uint32 size, bool clearFlag, int32 lineNum, const char *fname);
|
||||
void MemoryFree(void *v);
|
||||
|
||||
#define mallocAndZero(size) MemoryAlloc(size, true, __LINE__, __FILE__)
|
||||
#define MemAlloc(size) MemoryAlloc(size, false, __LINE__, __FILE__)
|
||||
#define MemFree(v) MemoryFree(v)
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
332
engines/cruise/ctp.cpp
Normal file
332
engines/cruise/ctp.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
/* 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 "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
uint8 *ctpVar17;
|
||||
|
||||
int currentWalkBoxCenterX;
|
||||
int currentWalkBoxCenterY;
|
||||
int currentWalkBoxCenterXBis;
|
||||
int currentWalkBoxCenterYBis;
|
||||
|
||||
int ctpVarUnk;
|
||||
uint8 walkboxTable[0x12];
|
||||
|
||||
int computeDistance(int varX, int varY, int paramX, int paramY) {
|
||||
int diffX = ABS(paramX - varX);
|
||||
int diffY = ABS(paramY - varY);
|
||||
|
||||
if (diffX > diffY) {
|
||||
diffY = diffX;
|
||||
}
|
||||
|
||||
return (diffY);
|
||||
}
|
||||
|
||||
// this function process path finding coordinates
|
||||
void computeAllDistance(int16 table[][10], short int coordCount) {
|
||||
for (int i = 0; i < coordCount; i++) {
|
||||
int x1 = ctp_routeCoords[i][0];
|
||||
int y1 = ctp_routeCoords[i][1];
|
||||
|
||||
for (int j = 0; j < ctp_routes[i][0]; j++) {
|
||||
int p = ctp_routes[i][j+1];
|
||||
|
||||
int x2 = ctp_routeCoords[p][0];
|
||||
int y2 = ctp_routeCoords[p][1];
|
||||
|
||||
table[i][p] = computeDistance(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getWalkBoxCenter(int n, int16 table[][40]) {
|
||||
int minX = 1000;
|
||||
int minY = 1000;
|
||||
int maxX = -1;
|
||||
int maxY = -1;
|
||||
|
||||
for (int i = 0; i < table[n][0]; i++) {
|
||||
int x = table[n][i*2+1];
|
||||
int y = table[n][i*2+2];
|
||||
|
||||
if (x < minX)
|
||||
minX = x;
|
||||
|
||||
if (x > maxX)
|
||||
maxX = x;
|
||||
|
||||
if (y < minY)
|
||||
minY = y;
|
||||
|
||||
if (y > maxY)
|
||||
maxY = y;
|
||||
}
|
||||
|
||||
currentWalkBoxCenterX = ((maxX - minX) / 2) + minX;
|
||||
currentWalkBoxCenterY = ((maxY - minY) / 2) + minY;
|
||||
}
|
||||
|
||||
// ax dx bx
|
||||
void renderCTPWalkBox(int16 *walkboxData, int hotPointX, int hotPointY, int X, int Y, int scale) {
|
||||
int numPoints;
|
||||
int16 *destination;
|
||||
|
||||
int startX = X - ((upscaleValue(hotPointX, scale) + 0x8000) >> 16);
|
||||
int startY = Y - ((upscaleValue(hotPointY, scale) + 0x8000) >> 16);
|
||||
|
||||
numPoints = *(walkboxData++);
|
||||
|
||||
destination = polyBuffer2;
|
||||
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
int pointX = *(walkboxData++);
|
||||
int pointY = *(walkboxData++);
|
||||
|
||||
int scaledX = ((upscaleValue(pointX, scale) + 0x8000) >> 16) + startX;
|
||||
int scaledY = ((upscaleValue(pointY, scale) + 0x8000) >> 16) + startY;
|
||||
|
||||
*(destination++) = scaledX;
|
||||
*(destination++) = scaledY;
|
||||
}
|
||||
|
||||
m_color = 0;
|
||||
ctpVarUnk = 0;
|
||||
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
walkboxTable[i] = i;
|
||||
}
|
||||
|
||||
drawPolyMode2((unsigned char *)walkboxTable, numPoints);
|
||||
}
|
||||
|
||||
// this process the walkboxes
|
||||
void makeCtStruct(Common::Array<CtStruct> &lst, int16 table[][40], int num, int z) {
|
||||
int minX = 1000;
|
||||
int maxX = -1;
|
||||
|
||||
if (table[num][0] < 1)
|
||||
return;
|
||||
|
||||
getWalkBoxCenter(num, table);
|
||||
|
||||
currentWalkBoxCenterXBis = currentWalkBoxCenterX;
|
||||
currentWalkBoxCenterYBis = currentWalkBoxCenterY;
|
||||
|
||||
renderCTPWalkBox(&table[num][0], currentWalkBoxCenterX, currentWalkBoxCenterY, currentWalkBoxCenterX, currentWalkBoxCenterY, z + 0x200);
|
||||
|
||||
lst.push_back(CtStruct());
|
||||
CtStruct &ct = lst[lst.size() - 1];
|
||||
|
||||
int16* XArray = XMIN_XMAX;
|
||||
int minY = *XArray++;
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (*XArray >= 0) {
|
||||
int x1 = *XArray++;
|
||||
int x2 = *XArray++;
|
||||
|
||||
if (x1 < minX)
|
||||
minX = x1;
|
||||
|
||||
if (x2 > maxX)
|
||||
maxX = x2;
|
||||
|
||||
ct.slices.push_back(CtEntry(x1, x2));
|
||||
i++;
|
||||
}
|
||||
|
||||
ct.num = num;
|
||||
ct.color = walkboxColor[num];
|
||||
ct.bounds.left = minX;
|
||||
ct.bounds.right = maxX;
|
||||
ct.bounds.top = minY;
|
||||
ct.bounds.bottom = minY + i;
|
||||
}
|
||||
|
||||
int getNode(int nodeResult[2], int nodeId) {
|
||||
if (nodeId < 0 || nodeId >= ctp_routeCoordCount)
|
||||
return -1;
|
||||
|
||||
nodeResult[0] = ctp_routeCoords[nodeId][0];
|
||||
nodeResult[1] = ctp_routeCoords[nodeId][1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setNodeColor(int nodeIdx, int nodeColor) {
|
||||
if (nodeIdx < 0 || nodeIdx >= ctp_routeCoordCount)
|
||||
return -1;
|
||||
|
||||
int oldColor = walkboxColor[nodeIdx];
|
||||
|
||||
if (nodeColor == -1)
|
||||
return
|
||||
|
||||
walkboxColor[nodeIdx] = nodeColor;
|
||||
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
int setNodeState(int nodeIdx, int nodeState) {
|
||||
if (nodeIdx < 0 || nodeIdx >= ctp_routeCoordCount)
|
||||
return -1;
|
||||
|
||||
int oldState = walkboxState[nodeIdx];
|
||||
|
||||
if (nodeState == -1)
|
||||
return oldState;
|
||||
|
||||
walkboxState[nodeIdx] = nodeState;
|
||||
|
||||
return oldState;
|
||||
}
|
||||
|
||||
int initCt(const char *ctpName) {
|
||||
uint8 *dataPointer; // ptr2
|
||||
char fileType[5]; // string2
|
||||
short int segementSizeTable[7]; // tempTable
|
||||
|
||||
if (!loadCtFromSave) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
persoTable[i] = nullptr;
|
||||
}
|
||||
}
|
||||
uint8* ptr = nullptr;
|
||||
if (!loadFileSub1(&ptr, ctpName, nullptr)) {
|
||||
MemFree(ptr);
|
||||
return (-18);
|
||||
}
|
||||
|
||||
dataPointer = ptr;
|
||||
|
||||
fileType[4] = 0;
|
||||
memcpy(fileType, dataPointer, 4); // get the file type, first 4 bytes of the CTP file
|
||||
dataPointer += 4;
|
||||
|
||||
if (strcmp(fileType, "CTP ")) {
|
||||
MemFree(ptr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
ctp_routeCoordCount = (int16)READ_BE_UINT16(dataPointer); // get the number of nods
|
||||
dataPointer += 2;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
segementSizeTable[i] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
|
||||
// get the path-finding coordinates
|
||||
assert((segementSizeTable[0] % 4) == 0);
|
||||
for (int i = 0; i < segementSizeTable[0] / 4; i++) {
|
||||
ctp_routeCoords[i][0] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
ctp_routeCoords[i][1] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
|
||||
// get the path-finding line informations (indexing the routeCoords array)
|
||||
assert((segementSizeTable[1] % 20) == 0);
|
||||
for (int i = 0; i < segementSizeTable[1] / 20; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ctp_routes[i][j] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// read polygons
|
||||
assert((segementSizeTable[2] % 80) == 0);
|
||||
for (int i = 0; i < segementSizeTable[2] / 80; i++) {
|
||||
for (int j = 0; j < 40; j++) {
|
||||
ctp_walkboxTable[i][j] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (loadCtFromSave) {
|
||||
// loading from save, ignore the initial values
|
||||
dataPointer += segementSizeTable[3];
|
||||
dataPointer += segementSizeTable[4];
|
||||
} else {
|
||||
// get the walkbox type
|
||||
// Type: 0x00 - non walkable, 0x01 - walkable, 0x02 - exit zone
|
||||
assert((segementSizeTable[3] % 2) == 0);
|
||||
for (int i = 0; i < segementSizeTable[3] / 2; i++) {
|
||||
walkboxColor[i] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
|
||||
// change indicator, walkbox type can change, i.e. blocked by object (values are either 0x00 or 0x01)
|
||||
assert((segementSizeTable[4] % 2) == 0);
|
||||
for (int i = 0; i < segementSizeTable[4] / 2; i++) {
|
||||
walkboxState[i] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
assert((segementSizeTable[5] % 2) == 0);
|
||||
for (int i = 0; i < segementSizeTable[5] / 2; i++) {
|
||||
walkboxColorIndex[i] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
|
||||
//
|
||||
assert((segementSizeTable[6] % 2) == 0);
|
||||
for (int i = 0; i < segementSizeTable[6] / 2; i++) {
|
||||
walkboxZoom[i] = (int16)READ_BE_UINT16(dataPointer);
|
||||
dataPointer += 2;
|
||||
}
|
||||
MemFree(ptr);
|
||||
|
||||
if (ctpName != currentCtpName)
|
||||
Common::strlcpy(currentCtpName, ctpName, 40);
|
||||
|
||||
numberOfWalkboxes = segementSizeTable[6] / 2; // get the number of walkboxes
|
||||
|
||||
computeAllDistance(distanceTable, ctp_routeCoordCount); // process path-finding stuff
|
||||
|
||||
// Load the polyStructNorm list
|
||||
|
||||
for (int i = numberOfWalkboxes - 1; i >= 0; i--) {
|
||||
makeCtStruct(_vm->_polyStructNorm, ctp_walkboxTable, i, 0);
|
||||
}
|
||||
|
||||
// Load the polyStructExp list
|
||||
|
||||
for (int i = numberOfWalkboxes - 1; i >= 0; i--) {
|
||||
makeCtStruct(_vm->_polyStructExp, ctp_walkboxTable, i, walkboxZoom[i] * 20);
|
||||
}
|
||||
|
||||
_vm->_polyStruct = _vm->_polyStructs = &_vm->_polyStructNorm;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
72
engines/cruise/ctp.h
Normal file
72
engines/cruise/ctp.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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 CRUISE_CTP_H
|
||||
#define CRUISE_CTP_H
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct ctpVar19SubStruct {
|
||||
uint16 boxIdx; //0
|
||||
uint16 type; //2
|
||||
uint16 minX; //4
|
||||
uint16 maxX; //6
|
||||
uint16 minY; //8
|
||||
uint16 maxY; //A
|
||||
};
|
||||
|
||||
struct ctpVar19Struct {
|
||||
struct ctpVar19Struct *field_0; //0
|
||||
ctpVar19SubStruct subStruct;
|
||||
};
|
||||
|
||||
class CtEntry {
|
||||
public:
|
||||
CtEntry(int16 xs, int16 xe) { minX = xs; maxX = xe; }
|
||||
CtEntry() { minX = 0; maxX = 0; }
|
||||
|
||||
int16 minX;
|
||||
int16 maxX;
|
||||
};
|
||||
|
||||
class CtStruct {
|
||||
public:
|
||||
CtStruct *next;
|
||||
int16 num;
|
||||
int16 color;
|
||||
Common::Rect bounds;
|
||||
Common::Array<CtEntry> slices;
|
||||
};
|
||||
|
||||
extern uint8 *ctpVar17;
|
||||
|
||||
int initCt(const char * ctpName);
|
||||
int computeDistance(int varX, int varY, int paramX, int paramY);
|
||||
|
||||
int getNode(int nodeResult[2], int nodeId);
|
||||
int setNodeColor(int nodeIdx, int nodeColor);
|
||||
int setNodeState(int nodeIdx, int nodeState);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
544
engines/cruise/dataLoader.cpp
Normal file
544
engines/cruise/dataLoader.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
enum fileTypeEnum {
|
||||
type_UNK,
|
||||
type_SPL,
|
||||
type_SET,
|
||||
type_FNT
|
||||
};
|
||||
|
||||
int loadSingleFile;
|
||||
|
||||
/**
|
||||
* Takes care of decoding a compressed graphic
|
||||
*/
|
||||
void decodeGfxUnified(dataFileEntry *pCurrentFileEntry, int16 format) {
|
||||
uint8 *dataPtr = pCurrentFileEntry->subData.ptr;
|
||||
int spriteSize;
|
||||
|
||||
// Unified how to get spriteSize
|
||||
switch (format) {
|
||||
case 1:
|
||||
case 4:
|
||||
spriteSize = pCurrentFileEntry->height * pCurrentFileEntry->width;
|
||||
break;
|
||||
case 5:
|
||||
spriteSize = pCurrentFileEntry->height * pCurrentFileEntry->widthInColumn;
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Unknown gfx format %d", format);
|
||||
}
|
||||
|
||||
uint8 *buffer = (uint8 *)MemAlloc(spriteSize);
|
||||
|
||||
// Perform format specific decoding
|
||||
switch (format) {
|
||||
case 1:
|
||||
case 4: {
|
||||
int x = 0;
|
||||
while (x < spriteSize) {
|
||||
uint8 c;
|
||||
uint16 p0;
|
||||
// Format 4
|
||||
uint16 p1 = 0, p2 = 0, p3 = 0;
|
||||
|
||||
p0 = (dataPtr[0] << 8) | dataPtr[1];
|
||||
|
||||
// Format 4
|
||||
if (format == 4) {
|
||||
p1 = (dataPtr[2] << 8) | dataPtr[3];
|
||||
p2 = (dataPtr[4] << 8) | dataPtr[5];
|
||||
p3 = (dataPtr[6] << 8) | dataPtr[7];
|
||||
}
|
||||
|
||||
/* decode planes */
|
||||
for (c = 0; c < 16; c++) {
|
||||
// Format 4
|
||||
if (format == 4) {
|
||||
buffer[x + c] = ((p0 >> 15) & 1) | ((p1 >> 14) & 2) | ((p2 >> 13) & 4) | ((p3 >> 12) & 8);
|
||||
} else {
|
||||
buffer[x + c] = ((p0 >> 15) & 1);
|
||||
}
|
||||
|
||||
p0 <<= 1;
|
||||
|
||||
// Format 4
|
||||
if (format == 4) {
|
||||
p1 <<= 1;
|
||||
p2 <<= 1;
|
||||
p3 <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
x += 16;
|
||||
|
||||
dataPtr += (2 * format);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
uint8 *destP = buffer;
|
||||
int range = pCurrentFileEntry->height * pCurrentFileEntry->width;
|
||||
|
||||
for (int line = 0; line < pCurrentFileEntry->height; line++) {
|
||||
uint8 p0, p1, p2, p3, p4;
|
||||
|
||||
for (int x = 0; x < pCurrentFileEntry->widthInColumn; x++) {
|
||||
int bit = 7 - (x % 8);
|
||||
int col = x / 8;
|
||||
|
||||
p0 = (dataPtr[line*pCurrentFileEntry->width + col + range * 0] >> bit) & 1;
|
||||
p1 = (dataPtr[line*pCurrentFileEntry->width + col + range * 1] >> bit) & 1;
|
||||
p2 = (dataPtr[line*pCurrentFileEntry->width + col + range * 2] >> bit) & 1;
|
||||
p3 = (dataPtr[line*pCurrentFileEntry->width + col + range * 3] >> bit) & 1;
|
||||
p4 = (dataPtr[line*pCurrentFileEntry->width + col + range * 4] >> bit) & 1;
|
||||
|
||||
*destP++ = p0 | (p1 << 1) | (p2 << 2) | (p3 << 3) | (p4 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MemFree(pCurrentFileEntry->subData.ptr);
|
||||
pCurrentFileEntry->subData.ptr = buffer;
|
||||
}
|
||||
|
||||
int updateResFileEntry(int height, int width, int size, int entryNumber, int resType) {
|
||||
int div = 0;
|
||||
|
||||
resetFileEntry(entryNumber);
|
||||
|
||||
filesDatabase[entryNumber].subData.compression = 0;
|
||||
|
||||
int maskSize = size;
|
||||
|
||||
if (resType == 4) {
|
||||
div = maskSize / 4;
|
||||
} else if (resType == 5) {
|
||||
width = (width * 8) / 5;
|
||||
maskSize = MAX(size, height * width);
|
||||
}
|
||||
|
||||
filesDatabase[entryNumber].subData.ptr = (uint8 *)mallocAndZero(maskSize + div);
|
||||
|
||||
if (!filesDatabase[entryNumber].subData.ptr)
|
||||
return (-2);
|
||||
|
||||
filesDatabase[entryNumber].widthInColumn = width;
|
||||
filesDatabase[entryNumber].subData.ptrMask = (uint8 *) mallocAndZero(maskSize);
|
||||
filesDatabase[entryNumber].width = width / 8;
|
||||
filesDatabase[entryNumber].resType = resType;
|
||||
filesDatabase[entryNumber].height = height;
|
||||
filesDatabase[entryNumber].subData.index = -1;
|
||||
|
||||
return entryNumber;
|
||||
}
|
||||
|
||||
int createResFileEntry(int width, int height, int size, int resType) {
|
||||
error("Executing untested createResFileEntry");
|
||||
return 0; // for compilers that don't support NORETURN
|
||||
|
||||
#if 0
|
||||
int entryNumber;
|
||||
int div = 0;
|
||||
|
||||
int i = 0;
|
||||
for (; i < NUM_FILE_ENTRIES; i++) {
|
||||
if (!filesDatabase[i].subData.ptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= NUM_FILE_ENTRIES) {
|
||||
return (-19);
|
||||
}
|
||||
|
||||
entryNumber = i;
|
||||
|
||||
filesDatabase[entryNumber].subData.compression = 0;
|
||||
|
||||
if (resType == 4) {
|
||||
div = size / 4;
|
||||
} else if (resType == 5) {
|
||||
width = (width * 8) / 5;
|
||||
}
|
||||
|
||||
filesDatabase[entryNumber].subData.ptr = (uint8 *) mallocAndZero(size + div);
|
||||
|
||||
if (!filesDatabase[entryNumber].subData.ptr) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
filesDatabase[entryNumber].widthInColumn = width;
|
||||
filesDatabase[entryNumber].subData.ptrMask = filesDatabase[entryNumber].subData.ptr + size;
|
||||
filesDatabase[entryNumber].width = width / 8;
|
||||
filesDatabase[entryNumber].resType = resType;
|
||||
filesDatabase[entryNumber].height = height;
|
||||
filesDatabase[entryNumber].subData.index = -1;
|
||||
|
||||
return entryNumber;
|
||||
#endif
|
||||
}
|
||||
|
||||
fileTypeEnum getFileType(const char *name) {
|
||||
char extensionBuffer[16];
|
||||
|
||||
fileTypeEnum newFileType = type_UNK;
|
||||
|
||||
getFileExtension(name, extensionBuffer, sizeof(extensionBuffer));
|
||||
|
||||
if (!strcmp(extensionBuffer, ".SPL")) {
|
||||
newFileType = type_SPL;
|
||||
} else if (!strcmp(extensionBuffer, ".SET")) {
|
||||
newFileType = type_SET;
|
||||
} else if (!strcmp(extensionBuffer, ".FNT")) {
|
||||
newFileType = type_FNT;
|
||||
}
|
||||
|
||||
assert(newFileType != type_UNK);
|
||||
|
||||
return newFileType;
|
||||
}
|
||||
|
||||
int getNumMaxEntiresInSet(uint8 *ptr) {
|
||||
uint16 numEntries = READ_BE_UINT16(ptr + 4);
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
int loadFile(const char* name, int idx, int destIdx) {
|
||||
uint8 *ptr = nullptr;
|
||||
fileTypeEnum fileType;
|
||||
|
||||
fileType = getFileType(name);
|
||||
|
||||
loadFileSub1(&ptr, name, nullptr);
|
||||
|
||||
switch (fileType) {
|
||||
case type_SET: {
|
||||
|
||||
int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr);
|
||||
|
||||
if (destIdx > numMaxEntriesInSet) {
|
||||
MemFree(ptr);
|
||||
return 0; // exit if limit is reached
|
||||
}
|
||||
int res = loadSetEntry(name, ptr, destIdx, idx);
|
||||
MemFree(ptr);
|
||||
|
||||
return res;
|
||||
}
|
||||
case type_FNT: {
|
||||
int res = loadFNTSub(ptr, idx);
|
||||
MemFree(ptr);
|
||||
|
||||
return res;
|
||||
}
|
||||
case type_SPL: {
|
||||
// Sound file
|
||||
loadSPLSub(ptr, idx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unknown fileType in loadFile");
|
||||
}
|
||||
|
||||
MemFree(ptr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int loadFileRange(const char *name, int startIdx, int currentEntryIdx, int numIdx) {
|
||||
uint8 *ptr = nullptr;
|
||||
fileTypeEnum fileType;
|
||||
|
||||
fileType = getFileType(name);
|
||||
|
||||
loadFileSub1(&ptr, name, nullptr);
|
||||
|
||||
switch (fileType) {
|
||||
case type_SET: {
|
||||
int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr);
|
||||
|
||||
for (int i = 0; i < numIdx; i++) {
|
||||
if ((startIdx + i) > numMaxEntriesInSet) {
|
||||
MemFree(ptr);
|
||||
return 0; // exit if limit is reached
|
||||
}
|
||||
loadSetEntry(name, ptr, startIdx + i, currentEntryIdx + i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case type_FNT: {
|
||||
loadFNTSub(ptr, startIdx);
|
||||
break;
|
||||
}
|
||||
case type_SPL: {
|
||||
// Sound file
|
||||
loadSPLSub(ptr, startIdx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unknown fileType in loadFileRange");
|
||||
}
|
||||
|
||||
MemFree(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadFullBundle(const char *name, int startIdx) {
|
||||
uint8 *ptr = nullptr;
|
||||
fileTypeEnum fileType;
|
||||
|
||||
fileType = getFileType(name);
|
||||
|
||||
loadFileSub1(&ptr, name, nullptr);
|
||||
|
||||
if (ptr == nullptr)
|
||||
return 0;
|
||||
|
||||
switch (fileType) {
|
||||
case type_SET: {
|
||||
// Sprite set
|
||||
int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr); // get maximum number of sprites/animations in SET file
|
||||
|
||||
for (int i = 0; i < numMaxEntriesInSet; i++) {
|
||||
loadSetEntry(name, ptr, i, startIdx + i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case type_FNT: {
|
||||
// Font file
|
||||
loadFNTSub(ptr, startIdx);
|
||||
break;
|
||||
}
|
||||
case type_SPL: {
|
||||
// Sound file
|
||||
loadSPLSub(ptr, startIdx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unknown fileType in loadFullBundle");
|
||||
}
|
||||
|
||||
MemFree(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadFNTSub(uint8 *ptr, int destIdx) {
|
||||
uint8 *ptr2 = ptr + 4;
|
||||
loadFileVar1 = READ_BE_UINT32(ptr2);
|
||||
|
||||
int fileIndex;
|
||||
if (destIdx == -1)
|
||||
fileIndex = createResFileEntry(loadFileVar1, 1, loadFileVar1, 1);
|
||||
else
|
||||
fileIndex = updateResFileEntry(loadFileVar1, 1, loadFileVar1, destIdx, 1);
|
||||
|
||||
if (fileIndex < 0)
|
||||
error("Unable to load FNT resource");
|
||||
|
||||
uint8 *destPtr = filesDatabase[fileIndex].subData.ptr;
|
||||
|
||||
if (destPtr != nullptr) {
|
||||
memcpy(destPtr, ptr2, loadFileVar1);
|
||||
|
||||
destPtr = filesDatabase[fileIndex].subData.ptr;
|
||||
|
||||
bigEndianLongToNative((int32 *) destPtr);
|
||||
bigEndianLongToNative((int32 *)(destPtr + 4));
|
||||
flipGen(destPtr + 8, 6);
|
||||
|
||||
uint8 *currentPtr = destPtr + 14;
|
||||
|
||||
for (int i = 0; i < (int16)READ_UINT16(destPtr + 8); i++) {
|
||||
bigEndianLongToNative((int32 *) currentPtr);
|
||||
currentPtr += 4;
|
||||
|
||||
flipGen(currentPtr, 8);
|
||||
currentPtr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int loadSPLSub(uint8 *ptr, int destIdx) {
|
||||
int fileIndex;
|
||||
|
||||
if (destIdx == -1)
|
||||
fileIndex = createResFileEntry(loadFileVar1, 1, loadFileVar1, 1);
|
||||
else
|
||||
fileIndex = updateResFileEntry(loadFileVar1, 1, loadFileVar1, destIdx, 1);
|
||||
|
||||
if (fileIndex < 0)
|
||||
error("Unable to load SPL resource");
|
||||
|
||||
uint8* destPtr = filesDatabase[fileIndex].subData.ptr;
|
||||
memcpy(destPtr, ptr, loadFileVar1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentDestEntry) {
|
||||
uint8 *ptr3;
|
||||
int offset;
|
||||
int sec = 0;
|
||||
uint16 numIdx;
|
||||
|
||||
if (!strcmp((char *)ptr, "SEC"))
|
||||
sec = 1;
|
||||
|
||||
numIdx = READ_BE_UINT16(ptr + 4);
|
||||
ptr3 = ptr + 6;
|
||||
offset = currentEntryIdx * 16;
|
||||
|
||||
int resourceSize;
|
||||
int fileIndex;
|
||||
setHeaderEntry localBuffer;
|
||||
|
||||
Common::MemoryReadStream s4(ptr + offset + 6, 16);
|
||||
|
||||
localBuffer.offset = s4.readUint32BE();
|
||||
localBuffer.width = s4.readUint16BE();
|
||||
localBuffer.height = s4.readUint16BE();
|
||||
localBuffer.type = s4.readUint16BE();
|
||||
localBuffer.transparency = s4.readUint16BE() & 0x1F;
|
||||
localBuffer.hotspotY = s4.readUint16BE();
|
||||
localBuffer.hotspotX = s4.readUint16BE();
|
||||
|
||||
if (sec == 1)
|
||||
// Type 1: Width - (1*2) , Type 5: Width - (5*2)
|
||||
localBuffer.width -= localBuffer.type * 2;
|
||||
|
||||
resourceSize = localBuffer.width * localBuffer.height;
|
||||
|
||||
if (!sec && (localBuffer.type == 5))
|
||||
// Type 5: Width - (2*5)
|
||||
localBuffer.width -= 10;
|
||||
|
||||
if (currentDestEntry == -1)
|
||||
fileIndex = createResFileEntry(localBuffer.width, localBuffer.height, resourceSize, localBuffer.type);
|
||||
else
|
||||
fileIndex = updateResFileEntry(localBuffer.height, localBuffer.width, resourceSize, currentDestEntry, localBuffer.type);
|
||||
|
||||
if (fileIndex < 0)
|
||||
return -1; // TODO: buffer is not freed
|
||||
|
||||
if (!sec && (localBuffer.type == 5)) {
|
||||
// There are sometimes sprites with a reduced width than what their pixels provide.
|
||||
// The original handled this here by copy parts of each line - for ScummVM, we're
|
||||
// simply setting the width in bytes and letting the decoder do the rest
|
||||
filesDatabase[fileIndex].width += 2;
|
||||
}
|
||||
|
||||
uint8 *ptr5 = ptr3 + localBuffer.offset + numIdx * 16;
|
||||
memcpy(filesDatabase[fileIndex].subData.ptr, ptr5, resourceSize);
|
||||
|
||||
switch (localBuffer.type) {
|
||||
case 0: // polygon
|
||||
filesDatabase[fileIndex].subData.resourceType = OBJ_TYPE_POLY;
|
||||
filesDatabase[fileIndex].subData.index = currentEntryIdx;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn * 8;
|
||||
filesDatabase[fileIndex].subData.resourceType = OBJ_TYPE_BGMASK;
|
||||
decodeGfxUnified(&filesDatabase[fileIndex], localBuffer.type);
|
||||
filesDatabase[fileIndex].subData.index = currentEntryIdx;
|
||||
filesDatabase[fileIndex].subData.transparency = 0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn * 2;
|
||||
filesDatabase[fileIndex].subData.resourceType = OBJ_TYPE_SPRITE;
|
||||
decodeGfxUnified(&filesDatabase[fileIndex], localBuffer.type);
|
||||
filesDatabase[fileIndex].subData.index = currentEntryIdx;
|
||||
filesDatabase[fileIndex].subData.transparency = localBuffer.transparency % 0x10;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
filesDatabase[fileIndex].subData.resourceType = OBJ_TYPE_SPRITE;
|
||||
decodeGfxUnified(&filesDatabase[fileIndex], localBuffer.type);
|
||||
filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn;
|
||||
filesDatabase[fileIndex].subData.index = currentEntryIdx;
|
||||
filesDatabase[fileIndex].subData.transparency = localBuffer.transparency;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
filesDatabase[fileIndex].subData.resourceType = OBJ_TYPE_SPRITE;
|
||||
filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn;
|
||||
filesDatabase[fileIndex].subData.index = currentEntryIdx;
|
||||
filesDatabase[fileIndex].subData.transparency = localBuffer.transparency;
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("Unsupported gfx loading type: %d", localBuffer.type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (name != filesDatabase[fileIndex].subData.name)
|
||||
Common::strlcpy(filesDatabase[fileIndex].subData.name, name, sizeof(filesDatabase[fileIndex].subData.name));
|
||||
|
||||
// create the mask
|
||||
switch (localBuffer.type) {
|
||||
case 1:
|
||||
case 4:
|
||||
case 5:
|
||||
case 8:
|
||||
memset(filesDatabase[fileIndex].subData.ptrMask, 0, filesDatabase[fileIndex].width / 8 * filesDatabase[fileIndex].height);
|
||||
|
||||
for (int maskY = 0; maskY < filesDatabase[fileIndex].height; maskY++) {
|
||||
for (int maskX = 0; maskX < filesDatabase[fileIndex].width; maskX++) {
|
||||
if (*(filesDatabase[fileIndex].subData.ptr + filesDatabase[fileIndex].width * maskY + maskX) != filesDatabase[fileIndex].subData.transparency) {
|
||||
*(filesDatabase[fileIndex].subData.ptrMask + filesDatabase[fileIndex].width / 8 * maskY + maskX / 8) |= 0x80 >> (maskX & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: free
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
38
engines/cruise/dataLoader.h
Normal file
38
engines/cruise/dataLoader.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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 CRUISE_DATALOADER_H
|
||||
#define CRUISE_DATALOADER_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
int loadFNTSub(uint8 *ptr, int destIdx);
|
||||
int loadSPLSub(uint8 *ptr, int destIdx);
|
||||
int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentDestEntry);
|
||||
int loadFile(const char* name, int idx, int destIdx);
|
||||
int loadData(const char * name, int startIdx);
|
||||
int loadFileRange(const char * name, int param, int startIdx, int numIdx);
|
||||
int loadFileSub1(uint8 ** ptr, const char * name, uint8 * ptr2);
|
||||
int loadFullBundle(const char * name, int startIdx);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
108
engines/cruise/debugger.cpp
Normal file
108
engines/cruise/debugger.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 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 "cruise/debugger.h"
|
||||
#include "cruise/cell.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/object.h"
|
||||
#include "cruise/overlay.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
Debugger::Debugger(): GUI::Debugger() {
|
||||
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
|
||||
registerCmd("hotspots", WRAP_METHOD(Debugger, cmd_hotspots));
|
||||
registerCmd("items", WRAP_METHOD(Debugger, cmd_items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Preliminary command to list the currently loaded hotspots
|
||||
*/
|
||||
bool Debugger::cmd_hotspots(int argc, const char **argv) {
|
||||
const char *pObjType;
|
||||
objectParamsQuery params;
|
||||
|
||||
cellStruct *currentObject = cellHead.prev;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject->overlay > 0 && overlayTable[currentObject->overlay].alreadyLoaded &&
|
||||
(currentObject->type == OBJ_TYPE_SPRITE || currentObject->type == OBJ_TYPE_MASK ||
|
||||
currentObject->type == OBJ_TYPE_EXIT || currentObject->type == OBJ_TYPE_VIRTUAL)) {
|
||||
const char *pObjectName = getObjectName(currentObject->idx, overlayTable[currentObject->overlay].ovlData->arrayNameObj);
|
||||
|
||||
switch (currentObject->type) {
|
||||
case OBJ_TYPE_SPRITE:
|
||||
pObjType = "SPRITE";
|
||||
break;
|
||||
case OBJ_TYPE_MASK:
|
||||
pObjType = "MASK";
|
||||
break;
|
||||
case OBJ_TYPE_EXIT:
|
||||
pObjType = "EXIT";
|
||||
break;
|
||||
case OBJ_TYPE_VIRTUAL:
|
||||
pObjType = "VIRTUAL";
|
||||
break;
|
||||
default:
|
||||
pObjType = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
if (*pObjectName) {
|
||||
getMultipleObjectParam(currentObject->overlay, currentObject->idx, ¶ms);
|
||||
|
||||
debugPrintf("%s %s - %d,%d\n", pObjectName, pObjType, params.X, params.Y);
|
||||
}
|
||||
}
|
||||
|
||||
currentObject = currentObject->prev;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preliminary command to list the current items in the player's inventory
|
||||
*/
|
||||
bool Debugger::cmd_items(int argc, const char **argv) {
|
||||
for (int i = 1; i < numOfLoadedOverlay; i++) {
|
||||
ovlDataStruct *pOvlData = overlayTable[i].ovlData;
|
||||
|
||||
if (overlayTable[i].alreadyLoaded) {
|
||||
if (overlayTable[i].ovlData->arrayObject) {
|
||||
for (int j = 0; j < pOvlData->numObj; j++) {
|
||||
if (getObjectClass(i, j) != 3) {
|
||||
int16 returnVar;
|
||||
|
||||
getSingleObjectParam(i, j, 5, &returnVar);
|
||||
|
||||
if (returnVar < -1)
|
||||
debugPrintf("%s\n", getObjectName(j, pOvlData->arrayNameObj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
40
engines/cruise/debugger.h
Normal file
40
engines/cruise/debugger.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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 CRUISE_DEBUGGER_H
|
||||
#define CRUISE_DEBUGGER_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
class Debugger : public GUI::Debugger {
|
||||
public:
|
||||
Debugger();
|
||||
|
||||
private:
|
||||
bool cmd_hotspots(int argc, const char **argv);
|
||||
bool cmd_items(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
1385
engines/cruise/decompiler.cpp
Normal file
1385
engines/cruise/decompiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
121
engines/cruise/delphine-unpack.cpp
Normal file
121
engines/cruise/delphine-unpack.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/* 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/endian.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct UnpackCtx {
|
||||
int size, datasize;
|
||||
uint32 crc;
|
||||
uint32 chk;
|
||||
byte *dst;
|
||||
const byte *src;
|
||||
};
|
||||
|
||||
static int rcr(UnpackCtx *uc, int CF) {
|
||||
int rCF = (uc->chk & 1);
|
||||
uc->chk >>= 1;
|
||||
if (CF) {
|
||||
uc->chk |= 0x80000000;
|
||||
}
|
||||
return rCF;
|
||||
}
|
||||
|
||||
static int nextChunk(UnpackCtx *uc) {
|
||||
int CF = rcr(uc, 0);
|
||||
if (uc->chk == 0) {
|
||||
uc->chk = READ_BE_UINT32(uc->src);
|
||||
uc->src -= 4;
|
||||
uc->crc ^= uc->chk;
|
||||
CF = rcr(uc, 1);
|
||||
}
|
||||
return CF;
|
||||
}
|
||||
|
||||
static uint16 getCode(UnpackCtx *uc, byte numChunks) {
|
||||
uint16 c = 0;
|
||||
while (numChunks--) {
|
||||
c <<= 1;
|
||||
if (nextChunk(uc)) {
|
||||
c |= 1;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void unpackHelper1(UnpackCtx *uc, byte numChunks, byte addCount) {
|
||||
uint16 count = getCode(uc, numChunks) + addCount + 1;
|
||||
uc->datasize -= count;
|
||||
while (count--) {
|
||||
*uc->dst = (byte)getCode(uc, 8);
|
||||
--uc->dst;
|
||||
}
|
||||
}
|
||||
|
||||
static void unpackHelper2(UnpackCtx *uc, byte numChunks) {
|
||||
uint16 i = getCode(uc, numChunks);
|
||||
uint16 count = uc->size + 1;
|
||||
uc->datasize -= count;
|
||||
while (count--) {
|
||||
*uc->dst = *(uc->dst + i);
|
||||
--uc->dst;
|
||||
}
|
||||
}
|
||||
|
||||
bool delphineUnpack(byte *dst, const byte *src, int len) {
|
||||
UnpackCtx uc;
|
||||
uc.src = src + len - 4;
|
||||
uc.datasize = READ_BE_UINT32(uc.src);
|
||||
uc.src -= 4;
|
||||
uc.dst = dst + uc.datasize - 1;
|
||||
uc.size = 0;
|
||||
uc.crc = READ_BE_UINT32(uc.src);
|
||||
uc.src -= 4;
|
||||
uc.chk = READ_BE_UINT32(uc.src);
|
||||
uc.src -= 4;
|
||||
uc.crc ^= uc.chk;
|
||||
do {
|
||||
if (!nextChunk(&uc)) {
|
||||
uc.size = 1;
|
||||
if (!nextChunk(&uc)) {
|
||||
unpackHelper1(&uc, 3, 0);
|
||||
} else {
|
||||
unpackHelper2(&uc, 8);
|
||||
}
|
||||
} else {
|
||||
uint16 c = getCode(&uc, 2);
|
||||
if (c == 3) {
|
||||
unpackHelper1(&uc, 8, 8);
|
||||
} else if (c < 2) {
|
||||
uc.size = c + 2;
|
||||
unpackHelper2(&uc, c + 9);
|
||||
} else {
|
||||
uc.size = getCode(&uc, 8);
|
||||
unpackHelper2(&uc, 12);
|
||||
}
|
||||
}
|
||||
} while (uc.datasize > 0);
|
||||
return uc.crc == 0;
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
279
engines/cruise/detection.cpp
Normal file
279
engines/cruise/detection.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/* 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 "cruise/detection.h"
|
||||
#include "cruise/cruise.h"
|
||||
|
||||
static const PlainGameDescriptor cruiseGames[] = {
|
||||
{"cruise", "Cruise for a Corpse"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Cruise::kCruiseDebugScript, "scripts", "Scripts debug level"},
|
||||
{Cruise::kCruiseDebugSound, "sound", "Sound debug level"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
static const CRUISEGameDescription gameDescriptions[] = {
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"16 colors",
|
||||
AD_ENTRY1("D1", "cd29a4cd9162076e9a18495fe56a48f3"),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"16 colors",
|
||||
AD_ENTRY1("D1", "41a7a4d426dbd048eb369cfee4bb2717"),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"256 colors",
|
||||
AD_ENTRY1("D1", "a90d2b9ead6b4d812cd14268672cf178"),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"256 colors",
|
||||
AD_ENTRY1("D1", "e258865807ea31b2d523340e6f0a606b"),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"16 colors",
|
||||
AD_ENTRY1("D1", "287d2ec1799e2f881dee23c70be96e81"),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"256 colors",
|
||||
AD_ENTRY1("D1", "f2a26522d49983c4ae32bcccbb801b02"),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"256 colors",
|
||||
AD_ENTRY1("D1", "e19a4ab2e24a69087e4ea994a5506231"),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
"256 colors",
|
||||
AD_ENTRY1("D1", "9a302ada55600d96061fda1d63a6ccda"),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Fanmade translation by old-games.ru
|
||||
{
|
||||
"cruise",
|
||||
"256 colors",
|
||||
AD_ENTRY1s("D1", "39b0f99d38be6da2af54af988efd58f1", 754587),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1("D1", "70f42a21cc257b01d58667853335f4f1"),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga English US GOLD edition.
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1("D1", "a9ff0e8b6ad2c08ccc3100d6b321e7b4"),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga English US GOLD edition (Delphine Collection).
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1("D1", "de084e9d2c6e4b2cc14803bf849eda3e"),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga Italian US GOLD edition.
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1("D1", "a0011075413b7335e003e8e3c9cf51b9"),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga Spanish edition.
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1s("D1", "b600d0892a2605b9ead63e1c86a8a0a3", 700576),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga French edition.
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1s("D1", "2d3e257103f0ee7427f8c81f9c3943f7", 701349),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga French edition (alternate).
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1s("D1", "d0433cda44dbcdef52eac709d7b04001", 700965),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // Amiga Italian (Fanmade translation 1.0).
|
||||
{
|
||||
"cruise",
|
||||
"Fanmade",
|
||||
AD_ENTRY1s("D1", "198ebe2f03d7ea7696b28fb31f1ed9ba", 700660),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // AtariST English KixxXL edition.
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1("D1", "be78614d5fa34bdb68bb03a2a6130280"),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAtariST,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{ // AtariST French edition. Bugreport #12824
|
||||
{
|
||||
"cruise",
|
||||
nullptr,
|
||||
AD_ENTRY1s("D1", "485ff850b7035316621f632e33f56468", 537311),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformAtariST,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_TTS)
|
||||
},
|
||||
},
|
||||
{AD_TABLE_END_MARKER}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class CruiseMetaEngineDetection : public AdvancedMetaEngineDetection<Cruise::CRUISEGameDescription> {
|
||||
public:
|
||||
CruiseMetaEngineDetection() : AdvancedMetaEngineDetection(Cruise::gameDescriptions, cruiseGames) {
|
||||
_guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI);
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "cruise";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Cinematique evo 2";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Cinematique evo 2 (C) Delphine Software";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(CRUISE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, CruiseMetaEngineDetection);
|
||||
37
engines/cruise/detection.h
Normal file
37
engines/cruise/detection.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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 CRUISE_DETECTION_H
|
||||
#define CRUISE_DETECTION_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct CRUISEGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
};
|
||||
|
||||
#define GAMEOPTION_TTS GUIO_GAMEOPTIONS1
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif // CRUISE_DETECTION_H
|
||||
438
engines/cruise/font.cpp
Normal file
438
engines/cruise/font.cpp
Normal file
@@ -0,0 +1,438 @@
|
||||
/* 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/endian.h"
|
||||
#include "common/file.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/mouse.h"
|
||||
#include "cruise/staticres.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
const int SPACE_WIDTH = 5;
|
||||
|
||||
/**
|
||||
* Determines the line size by finding the highest character in the given font set
|
||||
*/
|
||||
int32 getLineHeight(int16 charCount, const FontEntry *fontPtr) {
|
||||
int32 highestChar = 0;
|
||||
|
||||
if (!charCount)
|
||||
return (0);
|
||||
|
||||
for (int i = 0; i < charCount; ++i) {
|
||||
int charHeight = fontPtr[i].charHeight;
|
||||
if (charHeight > highestChar) highestChar = charHeight;
|
||||
}
|
||||
|
||||
return highestChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function determines how many lines the text will have
|
||||
*/
|
||||
int32 getTextLineCount(int32 rightBorder_X, int16 wordSpacingWidth,
|
||||
const FontEntry *fontData, const char *textString) {
|
||||
const char *localString = textString;
|
||||
const char *tempPtr = textString;
|
||||
uint8 ch;
|
||||
int32 total = 0, lineLength = 0;
|
||||
|
||||
if (rightBorder_X == 0)
|
||||
error("getTextLineCount() - invalid parameter");
|
||||
|
||||
if (!*textString)
|
||||
return (0);
|
||||
|
||||
ch = *localString;
|
||||
|
||||
do {
|
||||
int32 charData = fontCharacterTable[ch];
|
||||
|
||||
if (ch == '|') {
|
||||
lineLength = rightBorder_X;
|
||||
localString = tempPtr;
|
||||
} else if (charData >= 0) {
|
||||
lineLength += wordSpacingWidth + (int16)fontData[charData].charWidth;
|
||||
} else if (ch == ' ') {
|
||||
lineLength += wordSpacingWidth + SPACE_WIDTH;
|
||||
localString = tempPtr;
|
||||
}
|
||||
|
||||
if (lineLength >= rightBorder_X) {
|
||||
total += rightBorder_X;
|
||||
tempPtr = localString;
|
||||
lineLength = 0;
|
||||
}
|
||||
|
||||
ch = *++tempPtr;
|
||||
} while (ch);
|
||||
|
||||
if (lineLength > 0)
|
||||
total += rightBorder_X;
|
||||
|
||||
|
||||
return (total / rightBorder_X);
|
||||
}
|
||||
|
||||
void loadFNT(const char *fileName) {
|
||||
uint8 header[4];
|
||||
|
||||
_systemFNT = nullptr;
|
||||
|
||||
Common::File fontFileHandle;
|
||||
|
||||
if (!fontFileHandle.exists(fileName))
|
||||
return;
|
||||
|
||||
fontFileHandle.open((const char *)fileName);
|
||||
|
||||
fontFileHandle.read(header, 4);
|
||||
|
||||
if (strcmp((char *)header, "FNT") == 0) {
|
||||
uint32 fontSize = fontFileHandle.readUint32BE();
|
||||
|
||||
_systemFNT = (uint8 *)mallocAndZero(fontSize);
|
||||
|
||||
if (_systemFNT != nullptr) {
|
||||
fontFileHandle.seek(4);
|
||||
fontFileHandle.read(_systemFNT, fontSize);
|
||||
|
||||
// Flip structure values from BE to LE for font files - this is for consistency
|
||||
// with font resources, which are in LE formatt
|
||||
FontInfo *f = (FontInfo *)_systemFNT;
|
||||
bigEndianLongToNative(&f->offset);
|
||||
bigEndianLongToNative(&f->size);
|
||||
flipGen(&f->numChars, 6); // numChars, hSpacing, and vSpacing
|
||||
|
||||
FontEntry *fe = (FontEntry *)(_systemFNT + sizeof(FontInfo));
|
||||
|
||||
for (int i = 0; i < f->numChars; ++i, ++fe) {
|
||||
bigEndianLongToNative(&fe->offset); // Flip 32-bit offset field
|
||||
flipGen(&fe->v1, 8); // Flip remaining 16-bit fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fontFileHandle.close();
|
||||
}
|
||||
|
||||
void initSystem() {
|
||||
int32 i;
|
||||
|
||||
itemColor = 15;
|
||||
titleColor = 9;
|
||||
selectColor = 13;
|
||||
subColor = 10;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
preloadData[i].name[0] = '\0';
|
||||
preloadData[i].ptr = nullptr;
|
||||
preloadData[i].nofree = 0;
|
||||
}
|
||||
|
||||
doFade = 0;
|
||||
fadeFlag = 0;
|
||||
scroll = 0;
|
||||
switchPal = 0;
|
||||
masterScreen = 0;
|
||||
|
||||
changeCursor(CURSOR_NOMOUSE);
|
||||
changeCursor(CURSOR_NORMAL);
|
||||
mouseOn();
|
||||
|
||||
cmdLine[0] = '\0';
|
||||
|
||||
loadFNT("system.fnt");
|
||||
}
|
||||
|
||||
void freeSystem() {
|
||||
MemFree(_systemFNT);
|
||||
}
|
||||
|
||||
void bigEndianShortToNative(void *var) {
|
||||
WRITE_UINT16(var, READ_BE_UINT16(var));
|
||||
}
|
||||
|
||||
void bigEndianLongToNative(void *var) {
|
||||
WRITE_UINT32(var, READ_BE_UINT32(var));
|
||||
}
|
||||
|
||||
void flipGen(void *var, int32 length) {
|
||||
short int *varPtr = (int16 *) var;
|
||||
|
||||
for (int i = 0; i < (length / 2); i++) {
|
||||
bigEndianShortToNative(&varPtr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void renderWord(const uint8 *fontPtr_Data, uint8 *outBufferPtr, int xOffset, int yOffset,
|
||||
int32 height, int32 param4, int32 stringRenderBufferSize, int32 width, int32 charWidth) {
|
||||
const uint8 *fontPtr_Data2 = fontPtr_Data + height * 2;
|
||||
outBufferPtr += yOffset * width + xOffset;
|
||||
|
||||
for (int i = 0; i < height; i++) { // y++
|
||||
uint16 bitSet1 = READ_BE_UINT16(fontPtr_Data);
|
||||
uint16 bitSet2 = READ_BE_UINT16(fontPtr_Data2);
|
||||
|
||||
fontPtr_Data += sizeof(uint16);
|
||||
fontPtr_Data2 += sizeof(uint16);
|
||||
|
||||
for (int j = 0; j < charWidth; j++) {
|
||||
if (((bitSet1 >> 15) & 1)) {
|
||||
*outBufferPtr = ((bitSet2 >> 15) & 1) + 1;
|
||||
}
|
||||
outBufferPtr++;
|
||||
|
||||
bitSet1 <<= 1;
|
||||
bitSet2 <<= 1;
|
||||
}
|
||||
outBufferPtr += width - charWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// returns character count and pixel size (via pointer) per line of the string (old: prepareWordRender(int32 param, int32 var1, int16* out2, uint8* ptr3, uint8* string))
|
||||
int32 prepareWordRender(int32 inRightBorder_X, int16 wordSpacingWidth,
|
||||
int16 *strPixelLength, const FontEntry *fontData, const char *textString) {
|
||||
const char *localString = textString;
|
||||
|
||||
int32 counter = 0;
|
||||
int32 finish = 0;
|
||||
int32 temp_pc = 0; // var_A // temporary pixel count save
|
||||
int32 temp_cc = 0; // var_C // temporary char count save
|
||||
int32 pixelCount = 0; // si
|
||||
|
||||
do {
|
||||
uint8 character = *(localString++);
|
||||
int16 charData = fontCharacterTable[character];
|
||||
|
||||
if (character == ' ') {
|
||||
temp_cc = counter;
|
||||
temp_pc = pixelCount;
|
||||
|
||||
if (pixelCount + wordSpacingWidth + SPACE_WIDTH >=
|
||||
inRightBorder_X) {
|
||||
finish = 1;
|
||||
} else {
|
||||
pixelCount += wordSpacingWidth + SPACE_WIDTH;
|
||||
}
|
||||
} else {
|
||||
if (character == '|' || !character) {
|
||||
finish = 1;
|
||||
} else {
|
||||
if (charData >= 0) {
|
||||
if (pixelCount + wordSpacingWidth +
|
||||
(int16)fontData[charData].charWidth >= inRightBorder_X) {
|
||||
finish = 1;
|
||||
if (temp_pc) {
|
||||
pixelCount = temp_pc;
|
||||
counter = temp_cc;
|
||||
}
|
||||
} else {
|
||||
pixelCount += wordSpacingWidth +
|
||||
(int16)fontData[charData].charWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
counter++;
|
||||
} while (!finish);
|
||||
|
||||
*strPixelLength = (int16) pixelCount;
|
||||
return counter;
|
||||
}
|
||||
|
||||
void drawString(int32 x, int32 y, const char *string, uint8 *buffer, uint8 fontColor, int32 rightBorder_X) {
|
||||
|
||||
// Get the rendered text to display
|
||||
gfxEntryStruct *s = renderText(rightBorder_X, string);
|
||||
|
||||
// Draw the message
|
||||
drawMessage(s, x, y, rightBorder_X - x, fontColor, buffer);
|
||||
|
||||
_vm->sayText(string, Common::TextToSpeechManager::INTERRUPT);
|
||||
|
||||
// Free the data
|
||||
delete s->imagePtr;
|
||||
free(s);
|
||||
}
|
||||
|
||||
// calculates all necessary datas and renders text
|
||||
gfxEntryStruct *renderText(int inRightBorder_X, const char *string) {
|
||||
const FontInfo *fontPtr;
|
||||
const FontEntry *fontPtr_Desc;
|
||||
const uint8 *fontPtr_Data;
|
||||
int16 wordSpacingWidth; // 0 or -1
|
||||
int16 wordSpacingHeight;// 0 or -1
|
||||
int32 rightBorder_X;
|
||||
int32 lineHeight;
|
||||
int32 numLines;
|
||||
int32 stringHeight;
|
||||
int32 stringFinished;
|
||||
int32 stringWidth; // var_1C
|
||||
int32 stringRenderBufferSize;
|
||||
// int32 useDynamicBuffer;
|
||||
uint8 *currentStrRenderBuffer;
|
||||
// int32 var_8; // don't need that one
|
||||
int32 heightOffset; // var_12 // how much pixel-lines have already been drawn
|
||||
// int32 var_1E;
|
||||
gfxEntryStruct *generatedGfxEntry;
|
||||
|
||||
// check if string is empty
|
||||
if (!string) {
|
||||
return nullptr;
|
||||
}
|
||||
// check if font has been loaded, else get system font
|
||||
if (fontFileIndex != -1) {
|
||||
fontPtr = (const FontInfo *)filesDatabase[fontFileIndex].subData.ptr;
|
||||
|
||||
if (!fontPtr) {
|
||||
fontPtr = (const FontInfo *)_systemFNT;
|
||||
}
|
||||
} else {
|
||||
fontPtr = (const FontInfo *)_systemFNT;
|
||||
}
|
||||
|
||||
if (!fontPtr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fontPtr_Desc = (const FontEntry *)((const uint8 *)fontPtr + sizeof(FontInfo));
|
||||
fontPtr_Data = (const uint8 *)fontPtr + fontPtr->offset;
|
||||
|
||||
lineHeight = getLineHeight(fontPtr->numChars, fontPtr_Desc);
|
||||
|
||||
wordSpacingWidth = fontPtr->hSpacing;
|
||||
wordSpacingHeight = fontPtr->vSpacing;
|
||||
|
||||
// if right border is higher then screenwidth (+ spacing), adjust border
|
||||
if (inRightBorder_X > 310) {
|
||||
rightBorder_X = 310;
|
||||
} else {
|
||||
rightBorder_X = inRightBorder_X;
|
||||
}
|
||||
numLines = getTextLineCount(rightBorder_X, wordSpacingWidth, fontPtr_Desc, string); // ok
|
||||
|
||||
if (!numLines) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
stringHeight = ((wordSpacingHeight + lineHeight + 2) * numLines) + 1;
|
||||
stringFinished = 0;
|
||||
stringWidth = rightBorder_X + 2; // max render width to the right
|
||||
stringRenderBufferSize = stringWidth * stringHeight * 4;
|
||||
inRightBorder_X = rightBorder_X;
|
||||
|
||||
currentStrRenderBuffer =
|
||||
(uint8 *) mallocAndZero(stringRenderBufferSize);
|
||||
resetBitmap(currentStrRenderBuffer, stringRenderBufferSize);
|
||||
|
||||
generatedGfxEntry = (gfxEntryStruct *) MemAlloc(sizeof(gfxEntryStruct));
|
||||
generatedGfxEntry->imagePtr = currentStrRenderBuffer;
|
||||
generatedGfxEntry->imageSize = stringRenderBufferSize / 2;
|
||||
generatedGfxEntry->fontIndex = fontFileIndex;
|
||||
generatedGfxEntry->height = stringHeight;
|
||||
generatedGfxEntry->width = stringWidth; // maximum render width to the right
|
||||
|
||||
// var_8 = 0;
|
||||
heightOffset = 0;
|
||||
|
||||
do {
|
||||
int spacesCount = 0; // si
|
||||
unsigned char character = *string;
|
||||
short int strPixelLength; // var_16
|
||||
const char *ptrStringEnd; // var_4 //ok
|
||||
int drawPosPixel_X; // di
|
||||
|
||||
// find first letter in string, skip all spaces
|
||||
while (character == ' ') {
|
||||
spacesCount++;
|
||||
character = *(string + spacesCount);
|
||||
}
|
||||
|
||||
string += spacesCount;
|
||||
|
||||
// returns character count and pixel length (via pointer) per line of the text string
|
||||
ptrStringEnd = string + prepareWordRender(inRightBorder_X, wordSpacingWidth, &strPixelLength, fontPtr_Desc, string); //ok
|
||||
|
||||
// determine how much space is left to the right and left (center text)
|
||||
if (inRightBorder_X > strPixelLength) {
|
||||
//var_8 = (inRightBorder_X - strPixelLength) / 2;
|
||||
drawPosPixel_X =
|
||||
(inRightBorder_X - strPixelLength) / 2;
|
||||
} else {
|
||||
drawPosPixel_X = 0;
|
||||
}
|
||||
//drawPosPixel_X = var_8;
|
||||
|
||||
// draw textline, character wise
|
||||
do {
|
||||
character = *(string++);
|
||||
|
||||
short int charData = fontCharacterTable[character]; // get character position
|
||||
|
||||
if (character) {
|
||||
if (character == ' ' || character == 0x7C) {
|
||||
drawPosPixel_X += wordSpacingWidth + SPACE_WIDTH; // if char = "space" adjust word starting position (don't render space though);
|
||||
} else {
|
||||
if (charData >= 0) {
|
||||
const FontEntry &fe = fontPtr_Desc[charData];
|
||||
|
||||
// should ist be stringRenderBufferSize/2 for the second last param?
|
||||
renderWord((const uint8 *)fontPtr_Data + fe.offset,
|
||||
currentStrRenderBuffer,
|
||||
drawPosPixel_X,
|
||||
fe.height2 - fe.charHeight +
|
||||
lineHeight + heightOffset,
|
||||
fe.charHeight,
|
||||
fe.v1,
|
||||
stringRenderBufferSize,
|
||||
stringWidth,
|
||||
(int16)fe.charWidth);
|
||||
|
||||
drawPosPixel_X +=
|
||||
wordSpacingWidth + (int16)fe.charWidth;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stringFinished = 1; // character = 0x00
|
||||
}
|
||||
} while ((string < ptrStringEnd) && !stringFinished);
|
||||
|
||||
// var_8 = 0;
|
||||
heightOffset += wordSpacingHeight + lineHeight;
|
||||
} while (!stringFinished);
|
||||
|
||||
return generatedGfxEntry;
|
||||
}
|
||||
|
||||
void freeGfx(gfxEntryStruct *pGfx) {
|
||||
if (pGfx->imagePtr) {
|
||||
MemFree(pGfx->imagePtr);
|
||||
}
|
||||
|
||||
MemFree(pGfx);
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Cruise
|
||||
71
engines/cruise/font.h
Normal file
71
engines/cruise/font.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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 CRUISE_FONT_H
|
||||
#define CRUISE_FONT_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
struct FontInfo {
|
||||
uint32 size;
|
||||
uint32 offset;
|
||||
uint16 numChars;
|
||||
int16 hSpacing;
|
||||
int16 vSpacing;
|
||||
} PACKED_STRUCT;
|
||||
|
||||
struct FontEntry {
|
||||
uint32 offset;
|
||||
int16 v1;
|
||||
int16 charHeight;
|
||||
int16 height2;
|
||||
int16 charWidth;
|
||||
} PACKED_STRUCT;
|
||||
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
void loadFNT(const char *fileName);
|
||||
void initSystem();
|
||||
void freeSystem();
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
void bigEndianShortToNative(void *var);
|
||||
void bigEndianLongToNative(void *var); // TODO: move away
|
||||
void flipGen(void *var, int32 length);
|
||||
|
||||
int32 getLineHeight(int16 charCount, const FontEntry *fontPtr, const uint8 *fontPrt_Desc); // fontProc1
|
||||
int32 getTextLineCount(int32 rightBorder_X, int32 wordSpacingWidth, const FontEntry *fontData,
|
||||
const char *textString);
|
||||
void renderWord(uint8 *fontPtr_Data, uint8 *outBufferPtr,
|
||||
int32 drawPosPixel_X, int32 heightOff, int32 height, int32 param4,
|
||||
int32 stringRenderBufferSize, int32 width, int32 charWidth);
|
||||
gfxEntryStruct *renderText(int inRightBorder_X, const char *string);
|
||||
void drawString(int32 x, int32 y, const char *string, uint8 * buffer, uint8 fontColor,
|
||||
int32 inRightBorder_X);
|
||||
void freeGfx(gfxEntryStruct *pGfx);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
2019
engines/cruise/function.cpp
Normal file
2019
engines/cruise/function.cpp
Normal file
File diff suppressed because it is too large
Load Diff
38
engines/cruise/function.h
Normal file
38
engines/cruise/function.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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 CRUISE_FUNCTION_H
|
||||
#define CRUISE_FUNCTION_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
extern int flag_obstacle;
|
||||
extern int vblLimit;
|
||||
int32 opcodeType8();
|
||||
int16 computeZoom(int param);
|
||||
int16 subOp23(int param1, int param2);
|
||||
void freeObjectList(cellStruct *pListHead);
|
||||
int removeAnimation(actorStruct * pHead, int overlay, int objIdx, int objType);
|
||||
int16 Op_FadeOut();
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
370
engines/cruise/gfxModule.cpp
Normal file
370
engines/cruise/gfxModule.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/list.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
uint8 page00[320 * 200];
|
||||
uint8 page10[320 * 200];
|
||||
|
||||
palEntry lpalette[256];
|
||||
|
||||
int palDirtyMin = 256;
|
||||
int palDirtyMax = -1;
|
||||
|
||||
bool _dirtyRectScreen = false;
|
||||
|
||||
gfxModuleDataStruct gfxModuleData = {
|
||||
0, // use Tandy
|
||||
0, // use EGA
|
||||
1, // use VGA
|
||||
|
||||
page00, // pPage00
|
||||
page10, // pPage10
|
||||
};
|
||||
|
||||
void gfxModuleData_gfxClearFrameBuffer(uint8 *ptr) {
|
||||
memset(ptr, 0, 64000);
|
||||
}
|
||||
|
||||
void gfxModuleData_gfxCopyScreen(const uint8 *sourcePtr, uint8 *destPtr) {
|
||||
memcpy(destPtr, sourcePtr, 320 * 200);
|
||||
}
|
||||
|
||||
void outputBit(char *buffer, int bitPlaneNumber, uint8 data) {
|
||||
*(buffer + (8000 * bitPlaneNumber)) = data;
|
||||
}
|
||||
|
||||
void convertGfxFromMode4(const uint8 *sourcePtr, int width, int height, uint8 *destPtr) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width / 16; ++x) {
|
||||
for (int bit = 0; bit < 16; ++bit) {
|
||||
uint8 color = 0;
|
||||
for (int p = 0; p < 4; ++p) {
|
||||
if (READ_BE_UINT16(sourcePtr + p * 2) & (1 << (15 - bit))) {
|
||||
color |= 1 << p;
|
||||
}
|
||||
}
|
||||
*destPtr++ = color;
|
||||
}
|
||||
sourcePtr += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convertGfxFromMode5(const uint8 *sourcePtr, int width, int height, uint8 *destPtr) {
|
||||
int range = (width / 8) * height;
|
||||
|
||||
for (int line = 0; line < 200; line++) {
|
||||
uint8 p0;
|
||||
uint8 p1;
|
||||
uint8 p2;
|
||||
uint8 p3;
|
||||
uint8 p4;
|
||||
|
||||
for (int col = 0; col < 40; col++) {
|
||||
for (int bit = 0; bit < 8; bit++) {
|
||||
p0 = (sourcePtr[line*40 + col + range * 0] >> bit) & 1;
|
||||
p1 = (sourcePtr[line*40 + col + range * 1] >> bit) & 1;
|
||||
p2 = (sourcePtr[line*40 + col + range * 2] >> bit) & 1;
|
||||
p3 = (sourcePtr[line*40 + col + range * 3] >> bit) & 1;
|
||||
p4 = (sourcePtr[line*40 + col + range * 4] >> bit) & 1;
|
||||
|
||||
destPtr[line * width + col * 8 + (7-bit)] = p0 | (p1 << 1) | (p2 << 2) | (p3 << 3) | (p4 << 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gfxModuleData_setDirtyColors(int min, int max) {
|
||||
if (min < palDirtyMin)
|
||||
palDirtyMin = min;
|
||||
if (max > palDirtyMax)
|
||||
palDirtyMax = max;
|
||||
}
|
||||
|
||||
void gfxModuleData_setPalColor(int idx, int r, int g, int b) {
|
||||
lpalette[idx].R = r;
|
||||
lpalette[idx].G = g;
|
||||
lpalette[idx].B = b;
|
||||
gfxModuleData_setDirtyColors(idx, idx);
|
||||
}
|
||||
|
||||
void gfxModuleData_setPalEntries(const byte *ptr, int start, int num) {
|
||||
for (int i = start; i < start + num; i++) {
|
||||
int R = *(ptr++);
|
||||
int G = *(ptr++);
|
||||
int B = *(ptr++);
|
||||
|
||||
lpalette[i].R = R;
|
||||
lpalette[i].G = G;
|
||||
lpalette[i].B = B;
|
||||
lpalette[i].A = 255;
|
||||
}
|
||||
|
||||
gfxModuleData_setDirtyColors(start, start + num - 1);
|
||||
}
|
||||
|
||||
void gfxModuleData_setPal256(const byte *ptr) {
|
||||
gfxModuleData_setPalEntries(ptr, 0, 256);
|
||||
}
|
||||
|
||||
/*void gfxModuleData_setPal(uint8 *ptr) {
|
||||
int R;
|
||||
int G;
|
||||
int B;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
#define convertRatio 36.571428571428571428571428571429
|
||||
uint16 atariColor = *ptr;
|
||||
//bigEndianShortToNative(&atariColor);
|
||||
ptr ++;
|
||||
|
||||
R = (int)(convertRatio * ((atariColor & 0x700) >> 8));
|
||||
G = (int)(convertRatio * ((atariColor & 0x070) >> 4));
|
||||
B = (int)(convertRatio * ((atariColor & 0x007)));
|
||||
|
||||
if (R > 0xFF)
|
||||
R = 0xFF;
|
||||
if (G > 0xFF)
|
||||
G = 0xFF;
|
||||
if (B > 0xFF)
|
||||
B = 0xFF;
|
||||
|
||||
lpalette[i].R = R;
|
||||
lpalette[i].G = G;
|
||||
lpalette[i].B = B;
|
||||
lpalette[i].A = 255;
|
||||
}
|
||||
|
||||
gfxModuleData_setDirtyColors(0, 16);
|
||||
}*/
|
||||
|
||||
void gfxModuleData_convertOldPalColor(uint16 oldColor, uint8 *pOutput) {
|
||||
int R;
|
||||
int G;
|
||||
int B;
|
||||
|
||||
#define convertRatio 36.571428571428571428571428571429
|
||||
|
||||
R = (int)(convertRatio * ((oldColor & 0x700) >> 8));
|
||||
G = (int)(convertRatio * ((oldColor & 0x070) >> 4));
|
||||
B = (int)(convertRatio * ((oldColor & 0x007)));
|
||||
|
||||
if (R > 0xFF)
|
||||
R = 0xFF;
|
||||
if (G > 0xFF)
|
||||
G = 0xFF;
|
||||
if (B > 0xFF)
|
||||
B = 0xFF;
|
||||
|
||||
*(pOutput++) = R;
|
||||
*(pOutput++) = G;
|
||||
*(pOutput++) = B;
|
||||
}
|
||||
|
||||
void gfxModuleData_gfxWaitVSync() {
|
||||
}
|
||||
|
||||
void gfxModuleData_flip() {
|
||||
}
|
||||
|
||||
void gfxCopyRect(const uint8 *sourceBuffer, int width, int height, byte *dest, int x, int y, int color) {
|
||||
int xp, yp;
|
||||
|
||||
for (yp = 0; yp < height; ++yp) {
|
||||
const uint8 *srcP = &sourceBuffer[yp * width];
|
||||
uint8 *destP = &dest[(y + yp) * 320 + x];
|
||||
|
||||
for (xp = 0; xp < width; ++xp, ++srcP, ++destP) {
|
||||
uint8 v = *srcP;
|
||||
int xDest = x + xp;
|
||||
int yDest = y + yp;
|
||||
|
||||
if ((v != 0) && (xDest >= 0) && (yDest >= 0) && (xDest < 320) && (yDest < 200))
|
||||
*destP = (v == 1) ? 0 : color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gfxModuleData_Init() {
|
||||
memset(globalScreen, 0, 320 * 200);
|
||||
memset(page00, 0, 320 * 200);
|
||||
memset(page10, 0, 320 * 200);
|
||||
}
|
||||
|
||||
void gfxModuleData_flipScreen() {
|
||||
memcpy(globalScreen, gfxModuleData.pPage00, 320 * 200);
|
||||
|
||||
flip();
|
||||
}
|
||||
|
||||
void gfxModuleData_addDirtyRect(const Common::Rect &r) {
|
||||
_vm->_dirtyRects.push_back(Common::Rect( MAX(r.left, (int16)0), MAX(r.top, (int16)0),
|
||||
MIN(r.right, (int16)320), MIN(r.bottom, (int16)200)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the union of two rectangles.
|
||||
*/
|
||||
static bool unionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) {
|
||||
pDest.left = MIN(pSrc1.left, pSrc2.left);
|
||||
pDest.top = MIN(pSrc1.top, pSrc2.top);
|
||||
pDest.right = MAX(pSrc1.right, pSrc2.right);
|
||||
pDest.bottom = MAX(pSrc1.bottom, pSrc2.bottom);
|
||||
|
||||
return !pDest.isEmpty();
|
||||
}
|
||||
|
||||
static void mergeClipRects() {
|
||||
CruiseEngine::RectList::iterator rOuter, rInner;
|
||||
|
||||
for (rOuter = _vm->_dirtyRects.begin(); rOuter != _vm->_dirtyRects.end(); ++rOuter) {
|
||||
rInner = rOuter;
|
||||
while (++rInner != _vm->_dirtyRects.end()) {
|
||||
|
||||
if ((*rOuter).intersects(*rInner)) {
|
||||
// these two rectangles overlap, so translate it to a bigger rectangle
|
||||
// that contains both of them
|
||||
unionRectangle(*rOuter, *rOuter, *rInner);
|
||||
|
||||
// remove the inner rect from the list
|
||||
_vm->_dirtyRects.erase(rInner);
|
||||
|
||||
// move back to beginning of list
|
||||
rInner = rOuter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gfxModuleData_updatePalette() {
|
||||
byte paletteRGB[256 * 3];
|
||||
|
||||
if (palDirtyMax != -1) {
|
||||
for (int i = palDirtyMin; i <= palDirtyMax; i++) {
|
||||
paletteRGB[i * 3 + 0] = lpalette[i].R;
|
||||
paletteRGB[i * 3 + 1] = lpalette[i].G;
|
||||
paletteRGB[i * 3 + 2] = lpalette[i].B;
|
||||
}
|
||||
g_system->getPaletteManager()->setPalette(paletteRGB + palDirtyMin*3, palDirtyMin, palDirtyMax - palDirtyMin + 1);
|
||||
palDirtyMin = 256;
|
||||
palDirtyMax = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void gfxModuleData_updateScreen() {
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(20);
|
||||
}
|
||||
|
||||
void flip() {
|
||||
// Update the palette
|
||||
gfxModuleData_updatePalette();
|
||||
|
||||
// Make a copy of the prior frame's dirty rects, and then backup the current frame's rects
|
||||
CruiseEngine::RectList tempList = _vm->_priorFrameRects;
|
||||
_vm->_priorFrameRects = _vm->_dirtyRects;
|
||||
|
||||
// Merge the prior frame's dirty rects into the current frame's list
|
||||
for (auto &r : tempList) {
|
||||
_vm->_dirtyRects.push_back(Common::Rect(r.left, r.top, r.right, r.bottom));
|
||||
}
|
||||
|
||||
// Merge any overlapping rects to simplify the drawing process
|
||||
mergeClipRects();
|
||||
|
||||
// Copy any modified areas
|
||||
for (auto &r : _vm->_dirtyRects) {
|
||||
g_system->copyRectToScreen(globalScreen + 320 * r.top + r.left, 320,
|
||||
r.left, r.top, r.width(), r.height());
|
||||
}
|
||||
|
||||
_vm->_dirtyRects.clear();
|
||||
|
||||
// Allow the screen to update
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
void drawSolidBox(int32 x1, int32 y1, int32 x2, int32 y2, uint8 color) {
|
||||
for (int y = y1; y < y2; ++y) {
|
||||
byte *p = &gfxModuleData.pPage00[y * 320 + x1];
|
||||
Common::fill(p, p + (x2 - x1), color);
|
||||
}
|
||||
}
|
||||
|
||||
void resetBitmap(uint8 *dataPtr, int32 dataSize) {
|
||||
memset(dataPtr, 0, dataSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method compares a new background being switched in against the current background,
|
||||
* to figure out rectangles of changed areas for dirty rectangles
|
||||
*/
|
||||
void switchBackground(const byte *newBg) {
|
||||
const byte *bg = gfxModuleData.pPage00;
|
||||
|
||||
// If both the upper corners are different, presume it's a full screen change
|
||||
if ((*newBg != *bg) && (*(newBg + 319) != *(bg + 319))) {
|
||||
gfxModuleData_addDirtyRect(Common::Rect(0, 0, 320, 200));
|
||||
return;
|
||||
}
|
||||
|
||||
/* For an optimisation, any changes are stored as a series of slices than have a height of a single
|
||||
* line each. It is left up to the screen redraw code to automatically merge these together
|
||||
*/
|
||||
|
||||
for (int yp = 0; yp < 200; ++yp) {
|
||||
int sliceXStart = -1;
|
||||
int sliceXEnd = -1;
|
||||
for (int xp = 0; xp < 320; ++xp, ++bg, ++newBg) {
|
||||
if (*bg != *newBg) {
|
||||
if (sliceXStart == -1) {
|
||||
// Start of a new slice
|
||||
sliceXStart = xp;
|
||||
sliceXEnd = MIN(xp + 7, 320);
|
||||
} else
|
||||
// Carry on of changed area
|
||||
sliceXEnd = MAX(xp, sliceXEnd);
|
||||
|
||||
} else if ((sliceXEnd != -1) && (xp >= (sliceXEnd + 10))) {
|
||||
// If more than 10 pixels have gone by without any changes, then end the slice
|
||||
gfxModuleData_addDirtyRect(Common::Rect(sliceXStart, yp, sliceXEnd + 1, MIN(yp + 2, 200)));
|
||||
sliceXStart = sliceXEnd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sliceXStart != -1)
|
||||
gfxModuleData_addDirtyRect(Common::Rect(sliceXStart, yp, 320, MIN(yp + 2, 200)));
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
73
engines/cruise/gfxModule.h
Normal file
73
engines/cruise/gfxModule.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* 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 CRUISE_GFXMODULE_H
|
||||
#define CRUISE_GFXMODULE_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct gfxModuleDataStruct {
|
||||
int useTandy;
|
||||
int useEGA;
|
||||
int useVGA;
|
||||
|
||||
uint8 *pPage00;
|
||||
uint8 *pPage10;
|
||||
};
|
||||
|
||||
struct palEntry {
|
||||
uint8 R;
|
||||
uint8 G;
|
||||
uint8 B;
|
||||
uint8 A;
|
||||
};
|
||||
|
||||
extern gfxModuleDataStruct gfxModuleData;
|
||||
|
||||
void gfxModuleData_gfxClearFrameBuffer(uint8 *ptr);
|
||||
void gfxModuleData_setDirtyColors(int min, int max);
|
||||
void gfxModuleData_setPalColor(int idx, int r, int g, int b);
|
||||
void gfxModuleData_field_90();
|
||||
void gfxModuleData_gfxWaitVSync();
|
||||
void gfxModuleData_flip();
|
||||
void gfxModuleData_updatePalette();
|
||||
void gfxModuleData_updateScreen();
|
||||
|
||||
void gfxCopyRect(const uint8 *sourceBuffer, int width, int height, byte *dest, int x, int y, int color);
|
||||
void gfxModuleData_gfxCopyScreen(const uint8 *sourcePtr, uint8 *destPtr);
|
||||
void convertGfxFromMode4(const uint8 *sourcePtr, int width, int height, uint8 *destPtr);
|
||||
void convertGfxFromMode5(const uint8 *sourcePtr, int width, int height, uint8 *destPtr);
|
||||
void gfxModuleData_Init();
|
||||
void gfxModuleData_flipScreen();
|
||||
//void gfxModuleData_setPal(uint8 * ptr);
|
||||
void gfxModuleData_convertOldPalColor(uint16 oldColor, uint8 *pOutput);
|
||||
void gfxModuleData_setPalEntries(const byte *ptr, int start, int num);
|
||||
void gfxModuleData_setPal256(const byte *ptr);
|
||||
void gfxModuleData_addDirtyRect(const Common::Rect &r);
|
||||
void flip();
|
||||
void drawSolidBox(int32 x1, int32 y1, int32 x2, int32 y2, uint8 color);
|
||||
void resetBitmap(uint8 *dataPtr, int32 dataSize);
|
||||
|
||||
void switchBackground(const byte *newBg);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
269
engines/cruise/linker.cpp
Normal file
269
engines/cruise/linker.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/* 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/endian.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
exportEntryStruct *parseExport(int *out1, int *pExportedFuncionIdx, char *buffer) {
|
||||
char localBuffer[256];
|
||||
char functionName[256];
|
||||
char overlayName[256];
|
||||
char *dotPtr;
|
||||
char *ptr2;
|
||||
int idx;
|
||||
int numSymbGlob;
|
||||
exportEntryStruct *currentExportEntry;
|
||||
char *entity1Name;
|
||||
|
||||
*out1 = 0;
|
||||
*pExportedFuncionIdx = 0;
|
||||
|
||||
Common::strlcpy(localBuffer, buffer, sizeof(localBuffer));
|
||||
dotPtr = strchr(localBuffer, '.');
|
||||
|
||||
if (dotPtr) {
|
||||
Common::strlcpy(functionName, dotPtr + 1, sizeof(functionName));
|
||||
*dotPtr = 0;
|
||||
|
||||
Common::strcpy_s(overlayName, localBuffer);
|
||||
} else {
|
||||
overlayName[0] = 0;
|
||||
|
||||
Common::strlcpy(functionName, buffer, sizeof(functionName));
|
||||
}
|
||||
|
||||
ptr2 = strchr((char *)functionName, ':');
|
||||
|
||||
if (ptr2) {
|
||||
*ptr2 = 0;
|
||||
|
||||
*out1 = 1;
|
||||
}
|
||||
|
||||
strToUpper(overlayName);
|
||||
strToUpper(functionName);
|
||||
if (strlen((char *)overlayName) == 0)
|
||||
return nullptr;
|
||||
|
||||
idx = findOverlayByName2(overlayName);
|
||||
|
||||
if (idx == -4)
|
||||
return (nullptr);
|
||||
|
||||
if (overlayTable[idx].alreadyLoaded == 0)
|
||||
return (nullptr);
|
||||
|
||||
if (!overlayTable[idx].ovlData)
|
||||
return (nullptr);
|
||||
|
||||
numSymbGlob = overlayTable[idx].ovlData->numSymbGlob;
|
||||
currentExportEntry = overlayTable[idx].ovlData->arraySymbGlob;
|
||||
entity1Name = overlayTable[idx].ovlData->arrayNameSymbGlob;
|
||||
|
||||
if (!entity1Name)
|
||||
return (nullptr);
|
||||
|
||||
for (int i = 0; i < numSymbGlob; i++) {
|
||||
char exportedName[256];
|
||||
char *name = entity1Name + currentExportEntry->offsetToName;
|
||||
|
||||
Common::strlcpy(exportedName, name, sizeof(exportedName));
|
||||
strToUpper(exportedName);
|
||||
|
||||
if (!strcmp(functionName, exportedName)) {
|
||||
*pExportedFuncionIdx = idx;
|
||||
|
||||
return (currentExportEntry);
|
||||
}
|
||||
|
||||
currentExportEntry++;
|
||||
}
|
||||
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
int updateScriptImport(int ovlIdx) {
|
||||
char buffer[256];
|
||||
ovlDataStruct *ovlData;
|
||||
int numData3;
|
||||
int size5;
|
||||
int numRelocGlob;
|
||||
int param;
|
||||
int var_32;
|
||||
ovlData3Struct *pScript;
|
||||
// char* arrayRelocGlob;
|
||||
// char* namePtr;
|
||||
// char* arrayMsgRelHeader;
|
||||
|
||||
if (!overlayTable[ovlIdx].ovlData)
|
||||
return (-4);
|
||||
|
||||
ovlData = overlayTable[ovlIdx].ovlData;
|
||||
|
||||
numData3 = ovlData->numProc;
|
||||
size5 = ovlData->numRel;
|
||||
numRelocGlob = ovlData->numRelocGlob;
|
||||
param = 0;
|
||||
|
||||
// do it for the 2 first string types
|
||||
do {
|
||||
|
||||
if (param == 0) {
|
||||
var_32 = numData3;
|
||||
} else {
|
||||
var_32 = size5;
|
||||
}
|
||||
|
||||
if (var_32) {
|
||||
int i = 0;
|
||||
do {
|
||||
importScriptStruct *ptrImportData;
|
||||
const char *ptrImportName;
|
||||
uint8 *ptrData;
|
||||
|
||||
if (param == 0)
|
||||
pScript = getOvlData3Entry(ovlIdx, i);
|
||||
else
|
||||
pScript = scriptFunc1Sub2(ovlIdx, i);
|
||||
|
||||
ptrImportData = (importScriptStruct *)(pScript->dataPtr + pScript->offsetToImportData); // import data
|
||||
ptrImportName = (const char*)(pScript->dataPtr + pScript->offsetToImportName); // import name
|
||||
ptrData = pScript->dataPtr;
|
||||
|
||||
if (pScript->numRelocGlob > 0) {
|
||||
int counter = pScript->numRelocGlob;
|
||||
|
||||
do {
|
||||
int param2 = ptrImportData->type;
|
||||
|
||||
if (param2 != 70) {
|
||||
exportEntryStruct * ptrDest2;
|
||||
int out1;
|
||||
int out2;
|
||||
|
||||
Common::strlcpy(buffer, ptrImportName + ptrImportData->offsetToName, sizeof(buffer));
|
||||
ptrDest2 = parseExport(&out1, &out2, buffer);
|
||||
|
||||
if (ptrDest2 && out2) {
|
||||
int temp =
|
||||
ptrImportData->
|
||||
offset;
|
||||
if (out1) { //is sub function... (ie 'invent.livre:s')
|
||||
uint8 *ptr = ptrData + temp;
|
||||
|
||||
*(ptr + 1) = out2;
|
||||
WRITE_BE_UINT16(ptr + 2, ptrDest2->idx);
|
||||
} else {
|
||||
if (param2 == 20 || param2 == 30 || param2 == 40 || param2 == 50) { // this patch a double push
|
||||
uint8 *ptr = ptrData + temp;
|
||||
|
||||
*(ptr + 1) = 0;
|
||||
*(ptr + 2) = out2; // update the overlay number
|
||||
|
||||
WRITE_BE_UINT16(ptr + 4, ptrDest2->idx);
|
||||
} else {
|
||||
int var_4 = ptrDest2->var4;
|
||||
|
||||
if (var_4 & 1) {
|
||||
param2 = 8;
|
||||
} else {
|
||||
param2 = 16;
|
||||
}
|
||||
|
||||
if (var_4 >= 0 && var_4 <= 3) {
|
||||
param2 |= 5;
|
||||
} else {
|
||||
param2 |= 6;
|
||||
}
|
||||
|
||||
*(ptrData + temp) = param2;
|
||||
*(ptrData + temp + 1) = out2;
|
||||
|
||||
WRITE_BE_UINT16(ptrData + temp + 2, ptrDest2->idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptrImportData++;
|
||||
} while (--counter);
|
||||
}
|
||||
|
||||
} while (++i < var_32);
|
||||
|
||||
}
|
||||
|
||||
} while (++param < 2);
|
||||
|
||||
if (ovlData->arrayRelocGlob && ovlData->arrayNameRelocGlob && numRelocGlob) {
|
||||
int numImport2 = numRelocGlob;
|
||||
for (int i = 0; i < numImport2; i++) {
|
||||
int out1;
|
||||
int foundExportIdx;
|
||||
exportEntryStruct *pFoundExport;
|
||||
int linkType;
|
||||
int linkEntryIdx;
|
||||
|
||||
Common::strlcpy(buffer, ovlData->arrayNameRelocGlob + ovlData->arrayRelocGlob[i].nameOffset, sizeof(buffer));
|
||||
|
||||
pFoundExport = parseExport(&out1, &foundExportIdx, buffer);
|
||||
|
||||
linkType = ovlData->arrayRelocGlob[i].linkType;
|
||||
linkEntryIdx = ovlData->arrayRelocGlob[i].linkIdx;
|
||||
|
||||
if (pFoundExport && foundExportIdx) {
|
||||
switch (linkType) {
|
||||
case 0: { // verb
|
||||
ovlData->arrayMsgRelHeader[linkEntryIdx].verbOverlay = foundExportIdx;
|
||||
ovlData->arrayMsgRelHeader[linkEntryIdx].verbNumber = pFoundExport->idx;
|
||||
break;
|
||||
}
|
||||
case 1: { // obj1
|
||||
ovlData->arrayMsgRelHeader[linkEntryIdx].obj1Overlay = foundExportIdx;
|
||||
ovlData->arrayMsgRelHeader[linkEntryIdx].obj1Number = pFoundExport->idx;
|
||||
break;
|
||||
}
|
||||
case 2: { // obj2
|
||||
ovlData->arrayMsgRelHeader[linkEntryIdx].obj2Overlay = foundExportIdx;
|
||||
ovlData->arrayMsgRelHeader[linkEntryIdx].obj2Number = pFoundExport->idx;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
// check that the newly loaded isn't used by the already loaded overlays
|
||||
void updateAllScriptsImports() {
|
||||
for (int i = 0; i < 90; i++) {
|
||||
if (overlayTable[i].ovlData && overlayTable[i].alreadyLoaded)
|
||||
updateScriptImport(i);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
30
engines/cruise/linker.h
Normal file
30
engines/cruise/linker.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* 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 CRUISE_LINKER_H
|
||||
#define CRUISE_LINKER_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
void updateAllScriptsImports();
|
||||
|
||||
} // End of namespace Cruise
|
||||
#endif
|
||||
1575
engines/cruise/mainDraw.cpp
Normal file
1575
engines/cruise/mainDraw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
48
engines/cruise/mainDraw.h
Normal file
48
engines/cruise/mainDraw.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 CRUISE_MAINDRAW_H
|
||||
#define CRUISE_MAINDRAW_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
extern int currentTransparent;
|
||||
extern int16 *polyBuffer2;
|
||||
extern int16 *XMIN_XMAX;
|
||||
extern int m_color;
|
||||
|
||||
int upscaleValue(int value, int scale);
|
||||
|
||||
void pixel(int x, int y, char color);
|
||||
void mainDraw(bool waitFl);
|
||||
void flipScreen();
|
||||
void buildPolyModel(int X, int Y, int scale, char *ptr2, char *destBuffer, char *dataPtr);
|
||||
void drawSprite(int width, int height, cellStruct *currentObjPtr, const uint8 *dataIn, int ys, int xs, uint8 *output, const uint8 *dataBuf);
|
||||
void flipPoly(int fileId, int16 *dataPtr, int scale, char** newFrame, int X, int Y, int *outX, int *outY, int *outScale);
|
||||
void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], unsigned char *dataPtr);
|
||||
bool findPoly(char* dataPtr, int x, int y, int zoom, int mouseX, int mouseY);
|
||||
unsigned char *drawPolyMode2(unsigned char *dataPointer, int linesToDraw);
|
||||
void calcRGB(uint8* pColorSrc, uint8* pColorDst, int* offsetTable);
|
||||
void drawMessage(const gfxEntryStruct *pGfxPtr, int globalX, int globalY, int width, int newColor, uint8 *ouputPtr);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
344
engines/cruise/menu.cpp
Normal file
344
engines/cruise/menu.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
/* 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 "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/staticres.h"
|
||||
|
||||
#include "engines/metaengine.h"
|
||||
#include "gui/saveload.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
extern int currentMouseButton;
|
||||
|
||||
menuStruct *menuTable[8];
|
||||
|
||||
menuStruct *createMenu(int X, int Y, const char *menuName) {
|
||||
menuStruct *entry;
|
||||
|
||||
entry = (menuStruct *) MemAlloc(sizeof(menuStruct));
|
||||
assert(entry);
|
||||
|
||||
entry->x = X - 160 / 2;
|
||||
entry->y = Y;
|
||||
entry->stringPtr = menuName;
|
||||
entry->numElements = 0;
|
||||
entry->ptrNextElement = nullptr;
|
||||
entry->gfx = renderText(160, menuName);
|
||||
_vm->_menuJustOpened = true;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// TODO: rewrite to remove the goto
|
||||
void addSelectableMenuEntry(int ovlIdx, int headerIdx, menuStruct *pMenu, int param2, int color, const char *menuText) {
|
||||
menuElementStruct *di;
|
||||
menuElementStruct *var_6;
|
||||
menuElementStruct *pNewElement;
|
||||
menuElementSubStruct *pSubStruct;
|
||||
menuElementSubStruct *pSubStructCurrent;
|
||||
|
||||
if (pMenu->numElements <= 48) {
|
||||
var_6 = pMenu->ptrNextElement;
|
||||
|
||||
if (var_6) {
|
||||
do {
|
||||
di = var_6;
|
||||
if (param2) {
|
||||
if (!strcmp(var_6->string, menuText)) {
|
||||
pNewElement = var_6;
|
||||
pSubStruct = (menuElementSubStruct *)allocAndZero(sizeof(menuElementSubStruct));
|
||||
assert(pSubStruct);
|
||||
|
||||
pSubStruct->pNext = nullptr;
|
||||
pSubStruct->ovlIdx = ovlIdx;
|
||||
pSubStruct->header = headerIdx;
|
||||
|
||||
pSubStructCurrent = pNewElement->ptrSub;
|
||||
|
||||
if (!pSubStructCurrent) {
|
||||
pNewElement->ptrSub = pSubStruct;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pSubStructCurrent->pNext) {
|
||||
do {
|
||||
pSubStructCurrent = pSubStructCurrent->pNext;
|
||||
} while (pSubStructCurrent->pNext);
|
||||
}
|
||||
|
||||
pSubStructCurrent->pNext = pSubStruct;
|
||||
return;
|
||||
}
|
||||
}
|
||||
var_6 = var_6->next;
|
||||
} while (var_6);
|
||||
|
||||
var_6 = di;
|
||||
}
|
||||
|
||||
pNewElement = (menuElementStruct *)allocAndZero(sizeof(menuElementStruct));
|
||||
assert(pNewElement);
|
||||
pSubStruct = (menuElementSubStruct *)allocAndZero(sizeof(menuElementSubStruct));
|
||||
assert(pSubStruct);
|
||||
|
||||
pNewElement->string = menuText;
|
||||
pNewElement->next = nullptr;
|
||||
pNewElement->selected = false;
|
||||
pNewElement->color = color;
|
||||
pNewElement->gfx = renderText(160, menuText);
|
||||
|
||||
if (var_6 == nullptr) {
|
||||
pMenu->ptrNextElement = pNewElement;
|
||||
} else {
|
||||
var_6->next = pNewElement;
|
||||
}
|
||||
|
||||
pNewElement->ptrSub = pSubStruct;
|
||||
|
||||
pSubStruct->pNext = nullptr;
|
||||
pSubStruct->ovlIdx = ovlIdx;
|
||||
pSubStruct->header = headerIdx;
|
||||
|
||||
pMenu->numElements++;
|
||||
}
|
||||
}
|
||||
|
||||
void updateMenuMouse(int mouseX, int mouseY, menuStruct *pMenu) {
|
||||
bool menuItemSelected = false;
|
||||
|
||||
if (pMenu) {
|
||||
if (pMenu->gfx) {
|
||||
int height = pMenu->gfx->height; // rustine
|
||||
int var_2 = 0;
|
||||
menuElementStruct *pCurrentEntry = pMenu->ptrNextElement;
|
||||
|
||||
while (pCurrentEntry) {
|
||||
pCurrentEntry->selected = false;
|
||||
|
||||
if (var_2 == 0) {
|
||||
if ((mouseX > pCurrentEntry->x) && ((pCurrentEntry->x + 160) >= mouseX)) {
|
||||
if ((mouseY > pCurrentEntry->y) && ((pCurrentEntry->y + height) >= mouseY)) {
|
||||
var_2 = 1;
|
||||
pCurrentEntry->selected = true;
|
||||
|
||||
// Queue up the first selected item after opening the menu
|
||||
// This allows the name of the menu to be always voiced, in cases where something
|
||||
// is selected the instant the menu opens
|
||||
if (_vm->_menuJustOpened) {
|
||||
_vm->sayText(pCurrentEntry->string, Common::TextToSpeechManager::QUEUE);
|
||||
_vm->_menuJustOpened = false;
|
||||
} else {
|
||||
_vm->sayText(pCurrentEntry->string, Common::TextToSpeechManager::INTERRUPT);
|
||||
}
|
||||
|
||||
menuItemSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pCurrentEntry = pCurrentEntry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!menuItemSelected) {
|
||||
_vm->_previousSaid.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool manageEvents();
|
||||
|
||||
int processMenu(menuStruct *pMenu) {
|
||||
int16 mouseX;
|
||||
int16 mouseY;
|
||||
int16 mouseButton;
|
||||
int di;
|
||||
int si;
|
||||
currentActiveMenu = 0;
|
||||
|
||||
mainDraw(true);
|
||||
flipScreen();
|
||||
|
||||
di = 0;
|
||||
si = 0;
|
||||
|
||||
do {
|
||||
getMouseStatus(&main10, &mouseX, &mouseButton, &mouseY);
|
||||
|
||||
updateMenuMouse(mouseX, mouseY, pMenu);
|
||||
|
||||
if (mouseButton) {
|
||||
if (di) {
|
||||
si = 1;
|
||||
}
|
||||
} else {
|
||||
di = 1;
|
||||
}
|
||||
|
||||
mainDraw(true);
|
||||
flipScreen();
|
||||
|
||||
manageEvents();
|
||||
g_system->delayMillis(10);
|
||||
if (_vm->shouldQuit())
|
||||
return -1;
|
||||
|
||||
// readKeyboard();
|
||||
} while (!si);
|
||||
|
||||
currentActiveMenu = -1;
|
||||
|
||||
mainDraw(true);
|
||||
flipScreen();
|
||||
|
||||
if (mouseButton & 1) {
|
||||
menuElementSubStruct* pSelectedEntry = getSelectedEntryInMenu(pMenu);
|
||||
|
||||
if (pSelectedEntry) {
|
||||
return pSelectedEntry->header;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void handleSaveLoad(bool saveFlag) {
|
||||
if (saveFlag)
|
||||
_vm->saveGameDialog();
|
||||
else
|
||||
_vm->loadGameDialog();
|
||||
}
|
||||
|
||||
int playerMenu(int menuX, int menuY) {
|
||||
//int restartGame = 0;
|
||||
|
||||
if (playerMenuEnabled && displayOn) {
|
||||
if (remdo) {
|
||||
_vm->sound().stopMusic();
|
||||
freeStuff2();
|
||||
}
|
||||
/*
|
||||
if (currentMenu) {
|
||||
freeMenu(currentMenu);
|
||||
currentMenu = 0;
|
||||
selectDown = 0;
|
||||
menuDown = 0;
|
||||
main9 = -1;
|
||||
}
|
||||
|
||||
if (inventoryMenu) {
|
||||
freeMenu(inventoryMenu);
|
||||
inventoryMenu = 0;
|
||||
selectDown = 0;
|
||||
menuDown = 0;
|
||||
main9 = -1;
|
||||
}*/
|
||||
|
||||
/* if (mouseVar2) {
|
||||
free3(mouseVar2);
|
||||
} */
|
||||
|
||||
/* mouseVar2 = 0;
|
||||
linkedRelation = 0; */
|
||||
freeDisk();
|
||||
|
||||
menuTable[0] = createMenu(menuX, menuY, _vm->langString(ID_PLAYER_MENU));
|
||||
assert(menuTable[0]);
|
||||
_vm->sayText(_vm->langString(ID_PLAYER_MENU), Common::TextToSpeechManager::INTERRUPT);
|
||||
|
||||
//addSelectableMenuEntry(0, 3, menuTable[0], 1, -1, "Save game disk");
|
||||
if (userEnabled) {
|
||||
addSelectableMenuEntry(0, 4, menuTable[0], 1, -1, _vm->langString(ID_SAVE));
|
||||
}
|
||||
addSelectableMenuEntry(0, 5, menuTable[0], 1, -1, _vm->langString(ID_LOAD));
|
||||
addSelectableMenuEntry(0, 6, menuTable[0], 1, -1, _vm->langString(ID_RESTART));
|
||||
addSelectableMenuEntry(0, 7, menuTable[0], 1, -1, _vm->langString(ID_QUIT));
|
||||
|
||||
int retourMenu = processMenu(menuTable[0]);
|
||||
|
||||
freeMenu(menuTable[0]);
|
||||
menuTable[0] = nullptr;
|
||||
currentMouseButton = 0;
|
||||
|
||||
switch (retourMenu) {
|
||||
case 3: // select save drive
|
||||
break;
|
||||
case 4: // save
|
||||
case 5: // load
|
||||
handleSaveLoad(retourMenu == 4);
|
||||
break;
|
||||
case 6: // restart
|
||||
_vm->sound().fadeOutMusic();
|
||||
Op_FadeOut();
|
||||
memset(globalScreen, 0, 320 * 200);
|
||||
initVars();
|
||||
_vm->initAllData();
|
||||
changeCursor(CURSOR_NORMAL);
|
||||
userEnabled = 0;
|
||||
break;
|
||||
case 7: // exit
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freeMenu(menuStruct *pMenu) {
|
||||
menuElementStruct *pElement = pMenu->ptrNextElement;
|
||||
|
||||
while (pElement) {
|
||||
menuElementStruct *next;
|
||||
menuElementSubStruct *pSub = pElement->ptrSub;
|
||||
|
||||
next = pElement->next;
|
||||
|
||||
while (pSub) {
|
||||
menuElementSubStruct *nextSub;
|
||||
|
||||
nextSub = pSub->pNext;
|
||||
|
||||
MemFree(pSub);
|
||||
|
||||
pSub = nextSub;
|
||||
}
|
||||
|
||||
if (pElement->gfx) {
|
||||
freeGfx(pElement->gfx);
|
||||
}
|
||||
|
||||
MemFree(pElement);
|
||||
|
||||
pElement = next;
|
||||
}
|
||||
|
||||
freeGfx(pMenu->gfx);
|
||||
MemFree(pMenu);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
48
engines/cruise/menu.h
Normal file
48
engines/cruise/menu.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 CRUISE_MENU_H
|
||||
#define CRUISE_MENU_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct menuStruct {
|
||||
const char *stringPtr;
|
||||
gfxEntryStruct *gfx;
|
||||
int x;
|
||||
int y;
|
||||
int numElements;
|
||||
menuElementStruct *ptrNextElement;
|
||||
};
|
||||
|
||||
extern menuStruct *menuTable[8];
|
||||
|
||||
menuStruct *createMenu(int X, int Y, const char *menuName);
|
||||
void addSelectableMenuEntry(int var0, int var1, menuStruct * pMenu, int var2,
|
||||
int color, const char *menuText);
|
||||
void updateMenuMouse(int mouseX, int mouseY, menuStruct * pMenu);
|
||||
int processMenu(menuStruct * pMenu);
|
||||
void freeMenu(menuStruct * pMenu);
|
||||
int playerMenu(int menuX, int menuY);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
246
engines/cruise/metaengine.cpp
Normal file
246
engines/cruise/metaengine.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/* 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/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "common/translation.h"
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/saveload.h"
|
||||
#include "cruise/detection.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
#ifdef USE_TTS
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_TTS,
|
||||
{
|
||||
_s("Enable Text to Speech"),
|
||||
_s("Use TTS to read text in the game (if TTS is available)"),
|
||||
"tts_enabled",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
const char *CruiseEngine::getGameId() const {
|
||||
return _gameDescription->desc.gameId;
|
||||
}
|
||||
|
||||
Common::Language CruiseEngine::getLanguage() const {
|
||||
return _gameDescription->desc.language;
|
||||
}
|
||||
Common::Platform CruiseEngine::getPlatform() const {
|
||||
return _gameDescription->desc.platform;
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
class CruiseMetaEngine : public AdvancedMetaEngine<Cruise::CRUISEGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "cruise";
|
||||
}
|
||||
|
||||
#ifdef USE_TTS
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return Cruise::optionsList;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
int getMaximumSaveSlot() const override { return 99; }
|
||||
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const Cruise::CRUISEGameDescription *desc) const override;
|
||||
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool CruiseMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsDeleteSave) ||
|
||||
(f == kSavesSupportMetaInfo) ||
|
||||
(f == kSavesSupportThumbnail) ||
|
||||
(f == kSupportsLoadingDuringStartup);
|
||||
}
|
||||
|
||||
SaveStateList CruiseMetaEngine::listSaves(const char *target) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
Common::StringArray filenames;
|
||||
Common::String pattern("cruise.s##");
|
||||
|
||||
filenames = saveFileMan->listSavefiles(pattern);
|
||||
|
||||
SaveStateList saveList;
|
||||
for (const auto &filename : filenames) {
|
||||
// Obtain the last 2 digits of the filename, since they correspond to the save slot
|
||||
int slotNum = atoi(filename.c_str() + filename.size() - 2);
|
||||
|
||||
if (slotNum >= 0 && slotNum <= 99) {
|
||||
Common::InSaveFile *in = saveFileMan->openForLoading(filename);
|
||||
if (in) {
|
||||
Cruise::CruiseSavegameHeader header;
|
||||
if (Cruise::readSavegameHeader(in, header))
|
||||
saveList.push_back(SaveStateDescriptor(this, slotNum, header.saveName));
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
bool CruiseMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
return g_system->getSavefileManager()->removeSavefile(Cruise::CruiseEngine::getSavegameFile(slot));
|
||||
}
|
||||
|
||||
SaveStateDescriptor CruiseMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
|
||||
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(
|
||||
Cruise::CruiseEngine::getSavegameFile(slot));
|
||||
|
||||
if (f) {
|
||||
Cruise::CruiseSavegameHeader header;
|
||||
if (!Cruise::readSavegameHeader(f, header, false)) {
|
||||
delete f;
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
delete f;
|
||||
|
||||
// Create the return descriptor
|
||||
SaveStateDescriptor desc(this, slot, header.saveName);
|
||||
desc.setThumbnail(header.thumbnail);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
Common::Error CruiseMetaEngine::createInstance(OSystem *syst, Engine **engine, const Cruise::CRUISEGameDescription *desc) const {
|
||||
*engine = new Cruise::CruiseEngine(syst,desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::KeymapArray CruiseMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Cruise;
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "cruise-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);
|
||||
|
||||
// I18N: Game runs at faster speed
|
||||
act = new Action("FASTMODE", _("Fast mode"));
|
||||
act->setCustomEngineActionEvent(kActionFastMode);
|
||||
act->addDefaultInputMapping("C+f");
|
||||
act->addDefaultInputMapping("JOY_CENTER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("INVENTORY", _("Inventory"));
|
||||
act->setCustomEngineActionEvent(kActionInventory);
|
||||
act->addDefaultInputMapping("F9");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
// I18N: Opens menu with player commands
|
||||
act = new Action("PLAYERMENU", _("Player menu"));
|
||||
act->setCustomEngineActionEvent(kActionPlayerMenu);
|
||||
act->addDefaultInputMapping("F10");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("INCGAMESPEED", _("Increase game speed"));
|
||||
act->setCustomEngineActionEvent(kActionIncreaseGameSpeed);
|
||||
act->addDefaultInputMapping("KP_PLUS");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("DECGAMESPEED", _("Decrease game speed"));
|
||||
act->setCustomEngineActionEvent(kActionDecreaseGameSpeed);
|
||||
act->addDefaultInputMapping("KP_MINUS");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("PAUSE", _("Pause"));
|
||||
act->setCustomEngineActionEvent(kActionPause);
|
||||
act->addDefaultInputMapping("p");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_STICK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("ESC", _("Escape"));
|
||||
act->setCustomEngineActionEvent(kActionEscape);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("EXITGAME", _("Quit game"));
|
||||
act->setCustomEngineActionEvent(kActionExit);
|
||||
act->addDefaultInputMapping("x");
|
||||
act->addDefaultInputMapping("JOY_LEFT_STICK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
KeymapArray keymaps(2);
|
||||
keymaps[0] = engineKeyMap;
|
||||
keymaps[1] = gameKeyMap;
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(CRUISE)
|
||||
REGISTER_PLUGIN_DYNAMIC(CRUISE, PLUGIN_TYPE_ENGINE, CruiseMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(CRUISE, PLUGIN_TYPE_ENGINE, CruiseMetaEngine);
|
||||
#endif
|
||||
45
engines/cruise/module.mk
Normal file
45
engines/cruise/module.mk
Normal file
@@ -0,0 +1,45 @@
|
||||
MODULE := engines/cruise
|
||||
|
||||
MODULE_OBJS := \
|
||||
actor.o \
|
||||
background.o \
|
||||
backgroundIncrust.o \
|
||||
cell.o \
|
||||
cruise.o \
|
||||
cruise_main.o \
|
||||
ctp.o \
|
||||
dataLoader.o \
|
||||
debugger.o \
|
||||
decompiler.o \
|
||||
delphine-unpack.o \
|
||||
font.o \
|
||||
function.o \
|
||||
gfxModule.o \
|
||||
linker.o \
|
||||
mainDraw.o \
|
||||
menu.o \
|
||||
metaengine.o \
|
||||
mouse.o \
|
||||
object.o \
|
||||
overlay.o \
|
||||
perso.o \
|
||||
polys.o \
|
||||
saveload.o \
|
||||
script.o \
|
||||
sound.o \
|
||||
stack.o \
|
||||
staticres.o \
|
||||
various.o \
|
||||
vars.o \
|
||||
volume.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_CRUISE), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
95
engines/cruise/mouse.cpp
Normal file
95
engines/cruise/mouse.cpp
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/staticres.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
int16 main10;
|
||||
|
||||
struct MouseCursor {
|
||||
int hotspotX;
|
||||
int hotspotY;
|
||||
const byte *bitmap;
|
||||
};
|
||||
|
||||
static const MouseCursor mouseCursors[] = {
|
||||
{ 1, 1, mouseCursorNormal },
|
||||
{ 0, 0, mouseCursorDisk },
|
||||
{ 7, 7, mouseCursorCross },
|
||||
{ 0, 0, mouseCursorNoMouse },
|
||||
{ 10, 6, mouseCursorWalk },
|
||||
{ 10, 6, mouseCursorExit },
|
||||
{ 10, 6, mouseCursorMagnifyingGlass }
|
||||
};
|
||||
|
||||
CursorType currentCursor = CURSOR_NOMOUSE;
|
||||
|
||||
static const byte cursorPalette[] = {
|
||||
0, 0, 0,
|
||||
0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
void changeCursor(CursorType eType) {
|
||||
assert(eType >= 0 && eType < CURSOR_MAX);
|
||||
if (currentCursor != eType) {
|
||||
byte mouseCursor[16 * 16];
|
||||
const MouseCursor *mc = &mouseCursors[eType];
|
||||
const byte *src = mc->bitmap;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
int offs = i * 8;
|
||||
for (byte mask = 0x80; mask != 0; mask >>= 1) {
|
||||
if (src[0] & mask) {
|
||||
mouseCursor[offs] = 1;
|
||||
} else if (src[32] & mask) {
|
||||
mouseCursor[offs] = 0;
|
||||
} else {
|
||||
mouseCursor[offs] = 0xFF;
|
||||
}
|
||||
++offs;
|
||||
}
|
||||
++src;
|
||||
}
|
||||
CursorMan.replaceCursor(mouseCursor, 16, 16, mc->hotspotX, mc->hotspotY, 0xFF);
|
||||
CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
|
||||
currentCursor = eType;
|
||||
}
|
||||
}
|
||||
|
||||
bool isMouseOn() {
|
||||
return (currentCursor != CURSOR_NOMOUSE) && CursorMan.isVisible();
|
||||
}
|
||||
|
||||
void mouseOff() {
|
||||
CursorMan.showMouse(false);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
void mouseOn() {
|
||||
CursorMan.showMouse(true);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
50
engines/cruise/mouse.h
Normal file
50
engines/cruise/mouse.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 CRUISE_MOUSE_H
|
||||
#define CRUISE_MOUSE_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
extern int16 main10;
|
||||
|
||||
enum CursorType {
|
||||
CURSOR_NORMAL = 0,
|
||||
CURSOR_DISK = 1,
|
||||
CURSOR_CROSS = 2,
|
||||
CURSOR_NOMOUSE = 3,
|
||||
CURSOR_WALK = 4,
|
||||
CURSOR_EXIT = 5,
|
||||
CURSOR_MAGNIFYING_GLASS = 6,
|
||||
|
||||
CURSOR_MAX = 7
|
||||
};
|
||||
|
||||
void changeCursor(CursorType eType);
|
||||
bool isMouseOn();
|
||||
void mouseOff();
|
||||
void mouseOn();
|
||||
|
||||
extern CursorType currentCursor;
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
336
engines/cruise/object.cpp
Normal file
336
engines/cruise/object.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
/* 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/textconsole.h"
|
||||
|
||||
#include "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
//10 values:
|
||||
/*
|
||||
|
||||
0 = X
|
||||
1 = Y
|
||||
3 = fileIdx
|
||||
4 = scale
|
||||
|
||||
*/
|
||||
|
||||
objDataStruct *getObjectDataFromOverlay(int ovlIdx, int objIdx) {
|
||||
objDataStruct *var_6;
|
||||
|
||||
if (ovlIdx < 1 || objIdx < 0)
|
||||
return nullptr;
|
||||
|
||||
if (!overlayTable[ovlIdx].ovlData)
|
||||
return nullptr;
|
||||
|
||||
if (overlayTable[ovlIdx].ovlData->numObj <= objIdx)
|
||||
return nullptr;
|
||||
|
||||
var_6 = overlayTable[ovlIdx].ovlData->arrayObject;
|
||||
|
||||
if (!var_6)
|
||||
return nullptr;
|
||||
|
||||
return (&var_6[objIdx]);
|
||||
}
|
||||
|
||||
int16 getMultipleObjectParam(int16 overlayIdx, int16 objectIdx, objectParamsQuery *returnParam) {
|
||||
objectParams *ptr2 = nullptr;
|
||||
objDataStruct *ptr;
|
||||
ovlDataStruct *ovlData;
|
||||
// int16 type;
|
||||
|
||||
int state = 0;
|
||||
int state2 = 0;
|
||||
|
||||
ptr = getObjectDataFromOverlay(overlayIdx, objectIdx);
|
||||
|
||||
if (!ptr)
|
||||
return -11;
|
||||
|
||||
ovlData = overlayTable[overlayIdx].ovlData;
|
||||
|
||||
switch (ptr->_class) {
|
||||
case THEME:
|
||||
case MULTIPLE: {
|
||||
state = globalVars[overlayTable[overlayIdx].state + ptr->_stateTableIdx];
|
||||
|
||||
ptr2 = &ovlData->arrayStates[ptr->_firstStateIdx + state];
|
||||
|
||||
if (ptr->_firstStateIdx + state < 0) {
|
||||
debug(0, "Invalid Negative arrayState index in getMultipleObjectParam(overlayIdx: %d, objectIdx: %d)... Forcing to 0", overlayIdx, objectIdx);
|
||||
ptr2 = &ovlData->arrayStates[0];
|
||||
}
|
||||
|
||||
state2 = ptr2->state;
|
||||
break;
|
||||
}
|
||||
case VARIABLE: {
|
||||
ptr2 = &ovlData->arrayObjVar[ptr->_varTableIdx];
|
||||
|
||||
state = ptr2->state;
|
||||
state2 = state;
|
||||
if (ptr->_firstStateIdx + state < ovlData->size8) {
|
||||
objectParams *ptr3 = &ovlData->arrayStates[ptr->_firstStateIdx + state];
|
||||
state2 = ptr3->state;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
error("Unsupported case %d in getMultipleObjectParam", ptr->_class);
|
||||
}
|
||||
}
|
||||
|
||||
returnParam->X = ptr2->X;
|
||||
returnParam->Y = ptr2->Y;
|
||||
returnParam->baseFileIdx = ptr2->Z;
|
||||
returnParam->fileIdx = ptr2->frame;
|
||||
returnParam->scale = ptr2->scale;
|
||||
returnParam->state = state;
|
||||
returnParam->state2 = state2;
|
||||
returnParam->nbState = ptr->_numStates;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setObjectPosition(int16 ovlIdx, int16 objIdx, int16 param3, int16 param4) {
|
||||
objDataStruct *ptr = getObjectDataFromOverlay(ovlIdx, objIdx);
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
//overlayTable[param1].ovlData
|
||||
|
||||
switch (ptr->_class) {
|
||||
case THEME:
|
||||
case MULTIPLE: {
|
||||
if (param3 != 5)
|
||||
return;
|
||||
globalVars[overlayTable[ovlIdx].state + ptr->_stateTableIdx] = param4;
|
||||
sortCells(ovlIdx, objIdx, &cellHead);
|
||||
break;
|
||||
}
|
||||
case UNIQUE:
|
||||
return;
|
||||
case VARIABLE: {
|
||||
objectParams *ptr2 = &overlayTable[ovlIdx].ovlData->arrayObjVar[ptr->_varTableIdx];
|
||||
|
||||
switch (param3) {
|
||||
case 0: { // x
|
||||
ptr2->X = param4;
|
||||
break;
|
||||
}
|
||||
case 1: { // y
|
||||
ptr2->Y = param4;
|
||||
break;
|
||||
}
|
||||
case 2: { // z
|
||||
ptr2->Z = param4;
|
||||
sortCells(ovlIdx, objIdx, &cellHead);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
ptr2->frame = param4;
|
||||
break;
|
||||
}
|
||||
case 4: { // scale
|
||||
ptr2->scale = param4;
|
||||
break;
|
||||
}
|
||||
case 5: { // state
|
||||
ptr2->state = param4;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16 objInit(int ovlIdx, int objIdx, int newState) {
|
||||
objDataStruct *ptr;
|
||||
// uint16 param;
|
||||
ovlDataStruct *ovlData;
|
||||
|
||||
ptr = getObjectDataFromOverlay(ovlIdx, objIdx);
|
||||
|
||||
if (!ptr)
|
||||
return -11;
|
||||
|
||||
ovlData = overlayTable[ovlIdx].ovlData;
|
||||
|
||||
switch (ptr->_class) {
|
||||
case THEME:
|
||||
case MULTIPLE: {
|
||||
globalVars[overlayTable[ovlIdx].state + ptr->_stateTableIdx] = newState;
|
||||
sortCells(ovlIdx, objIdx, &cellHead);
|
||||
break;
|
||||
}
|
||||
case UNIQUE:
|
||||
break;
|
||||
case VARIABLE: {
|
||||
objectParams *destEntry;
|
||||
objectParams *sourceEntry;
|
||||
|
||||
if (ptr->_firstStateIdx + newState > ovlData->size8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
destEntry = &ovlData->arrayObjVar[ptr->_varTableIdx];
|
||||
sourceEntry = &ovlData->arrayStates[ptr->_firstStateIdx + newState];
|
||||
|
||||
memcpy(destEntry, sourceEntry, sizeof(objectParams));
|
||||
|
||||
destEntry->state = newState;
|
||||
|
||||
sortCells(ovlIdx, objIdx, &cellHead);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
warning("Unsupported param = %d in objInit", ptr->_class);
|
||||
// exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 getSingleObjectParam(int16 overlayIdx, int16 param2, int16 param3, int16 *returnParam) {
|
||||
int state = 0;
|
||||
//char* ptr3 = NULL;
|
||||
objDataStruct *ptr;
|
||||
ovlDataStruct *ovlData;
|
||||
objectParams *ptr2 = nullptr;
|
||||
|
||||
ptr = getObjectDataFromOverlay(overlayIdx, param2);
|
||||
|
||||
if (!ptr)
|
||||
return -11;
|
||||
|
||||
ovlData = overlayTable[overlayIdx].ovlData;
|
||||
|
||||
switch (ptr->_class) {
|
||||
case THEME:
|
||||
case MULTIPLE: {
|
||||
state = globalVars[overlayTable[overlayIdx].state + ptr->_stateTableIdx];
|
||||
|
||||
ptr2 = &ovlData->arrayStates[ptr->_firstStateIdx + state];
|
||||
|
||||
if (ptr->_firstStateIdx + state < 0) {
|
||||
debug(0, "Invalid Negative arrayState index in getSingleObjectParam(overlayIdx: %d, param2: %d, param3: %d)... Forcing to 0", overlayIdx, param2, param3);
|
||||
ptr2 = &ovlData->arrayStates[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VARIABLE: {
|
||||
ptr2 = &ovlData->arrayObjVar[ptr->_varTableIdx];
|
||||
|
||||
state = ptr2->state;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
error("Unsupported case %d in getSingleObjectParam", ptr->_class);
|
||||
}
|
||||
}
|
||||
|
||||
switch (param3) {
|
||||
case 0: {
|
||||
*returnParam = ptr2->X;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
*returnParam = ptr2->Y;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
*returnParam = ptr2->Z;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
*returnParam = ptr2->frame;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
*returnParam = ptr2->scale;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
*returnParam = state;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
error("Unsupported case %d in getSingleObjectParam case 1", param3);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void objectReset() {
|
||||
for (int i = 1; i < numOfLoadedOverlay; i++) {
|
||||
if (overlayTable[i].alreadyLoaded && overlayTable[i].ovlData) {
|
||||
if (overlayTable[i].ovlData->arrayObject) {
|
||||
for (int j = 0; j < overlayTable[i].ovlData->numObj; j++) {
|
||||
int stateIdx = overlayTable[i].state + overlayTable[i].ovlData->arrayObject[j]._stateTableIdx;
|
||||
if ((overlayTable[i].ovlData->arrayObject[j]._class == THEME) && (globalVars[stateIdx] == -2))
|
||||
globalVars[stateIdx] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *getObjectName(int index, const char *string) {
|
||||
const char *ptr = string;
|
||||
|
||||
if (!string)
|
||||
return nullptr;
|
||||
|
||||
int i = 0;
|
||||
// int j = 0;
|
||||
|
||||
while (i < index) {
|
||||
ptr += strlen(ptr) + 1;
|
||||
i++;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int getObjectClass(int overlayIdx, int objIdx) {
|
||||
objDataStruct *pObjectData = getObjectDataFromOverlay(overlayIdx, objIdx);
|
||||
|
||||
if (pObjectData) {
|
||||
return pObjectData->_class;
|
||||
} else {
|
||||
return -11;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
58
engines/cruise/object.h
Normal file
58
engines/cruise/object.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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 CRUISE_OBJECT_H
|
||||
#define CRUISE_OBJECT_H
|
||||
|
||||
#include "cruise/overlay.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct gfxEntryStruct {
|
||||
uint8 *imagePtr;
|
||||
int imageSize;
|
||||
int fontIndex;
|
||||
int height;
|
||||
int width; // for font: max right border; for sprite: just width
|
||||
};
|
||||
|
||||
|
||||
struct objectParamsQuery {
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 baseFileIdx;
|
||||
int16 fileIdx;
|
||||
int16 scale;
|
||||
int16 state;
|
||||
int16 state2;
|
||||
int16 nbState;
|
||||
};
|
||||
|
||||
objDataStruct *getObjectDataFromOverlay(int ovlIdx, int objIdx);
|
||||
int16 getSingleObjectParam(int16 overlayIdx, int16 param2, int16 param3, int16 * returnParam);
|
||||
int16 getMultipleObjectParam(int16 overlayIdx, int16 objectIdx, objectParamsQuery * returnParam);
|
||||
void objectReset();
|
||||
const char *getObjectName(int index, const char *string);
|
||||
int getObjectClass(int overlayIdx, int objIdx);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
680
engines/cruise/overlay.cpp
Normal file
680
engines/cruise/overlay.cpp
Normal file
@@ -0,0 +1,680 @@
|
||||
/* 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/memstream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
overlayStruct overlayTable[90];
|
||||
int numOfLoadedOverlay;
|
||||
|
||||
void initOverlayTable() {
|
||||
for (int i = 0; i < 90; i++) {
|
||||
overlayTable[i].overlayName[0] = 0;
|
||||
overlayTable[i].ovlData = nullptr;
|
||||
overlayTable[i].alreadyLoaded = 0;
|
||||
overlayTable[i].executeScripts = 0;
|
||||
}
|
||||
|
||||
numOfLoadedOverlay = 1;
|
||||
}
|
||||
|
||||
void freeOverlayTable() {
|
||||
for (int i = 0; i < 90; i++) {
|
||||
if (overlayTable[i].alreadyLoaded)
|
||||
freeOverlay(i);
|
||||
}
|
||||
}
|
||||
|
||||
int freeOverlay(int overlayIdx) {
|
||||
ovlDataStruct *ovlDataPtr;
|
||||
|
||||
if (overlayTable[overlayIdx].alreadyLoaded == 0)
|
||||
return -4;
|
||||
|
||||
overlayTable[overlayIdx].alreadyLoaded = 0;
|
||||
|
||||
ovlDataPtr = overlayTable[overlayIdx].ovlData;
|
||||
|
||||
if (!ovlDataPtr)
|
||||
return -4;
|
||||
|
||||
/*
|
||||
if (overlayTable[overlayIdx].var1E) {
|
||||
MemFree(overlayTable[overlayIdx].var1E);
|
||||
overlayTable[overlayIdx].var1E = NULL;
|
||||
}
|
||||
|
||||
if (overlayTable[overlayIdx].var16) {
|
||||
MemFree(overlayTable[overlayIdx].var16);
|
||||
overlayTable[overlayIdx].var16 = NULL;
|
||||
} */
|
||||
|
||||
removeScript(overlayIdx, -1, &procHead);
|
||||
removeScript(overlayIdx, -1, &procHead);
|
||||
|
||||
removeScript(overlayIdx, -1, &relHead);
|
||||
removeScript(overlayIdx, -1, &relHead);
|
||||
|
||||
if (ovlDataPtr->stringTable) {
|
||||
for (int i = 0; i < ovlDataPtr->numStrings; ++i)
|
||||
MemFree(ovlDataPtr->stringTable[i].string);
|
||||
MemFree(ovlDataPtr->stringTable);
|
||||
}
|
||||
if (ovlDataPtr->arrayProc) {
|
||||
ovlData3Struct *tempPtr = ovlDataPtr->arrayProc;
|
||||
for (int i = 0; i < ovlDataPtr->numProc; ++i, ++tempPtr)
|
||||
MemFree(tempPtr->dataPtr);
|
||||
MemFree(ovlDataPtr->arrayProc);
|
||||
}
|
||||
if (ovlDataPtr->ptr1) {
|
||||
ovlData3Struct *tempPtr = (ovlData3Struct *)ovlDataPtr->ptr1;
|
||||
for (int i = 0; i < ovlDataPtr->numRel; ++i, ++tempPtr)
|
||||
MemFree(tempPtr->dataPtr);
|
||||
MemFree(ovlDataPtr->ptr1);
|
||||
}
|
||||
|
||||
MemFree(ovlDataPtr->arraySymbGlob);
|
||||
MemFree(ovlDataPtr->arrayNameSymbGlob);
|
||||
MemFree(ovlDataPtr->data4Ptr);
|
||||
MemFree(ovlDataPtr->arrayMsgRelHeader);
|
||||
MemFree(ovlDataPtr->ptr8);
|
||||
MemFree(ovlDataPtr->arrayObject);
|
||||
MemFree(ovlDataPtr->arrayObjVar);
|
||||
MemFree(ovlDataPtr->arrayStates);
|
||||
MemFree(ovlDataPtr->nameVerbGlob);
|
||||
MemFree(ovlDataPtr->arrayNameObj);
|
||||
MemFree(ovlDataPtr->arrayRelocGlob);
|
||||
MemFree(ovlDataPtr->arrayNameRelocGlob);
|
||||
|
||||
MemFree(ovlDataPtr);
|
||||
overlayTable[overlayIdx].ovlData = nullptr;
|
||||
|
||||
debug(1, "freeOverlay: finish !");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadOverlay(const char *scriptName) {
|
||||
int newNumberOfScript;
|
||||
bool scriptNotLoadedBefore;
|
||||
int scriptIdx;
|
||||
char fileName[50];
|
||||
int fileIdx;
|
||||
int unpackedSize;
|
||||
byte *unpackedBuffer;
|
||||
ovlDataStruct *ovlData;
|
||||
|
||||
debug(1, "Load overlay: %s", scriptName);
|
||||
|
||||
newNumberOfScript = numOfLoadedOverlay;
|
||||
|
||||
scriptNotLoadedBefore = false;
|
||||
|
||||
scriptIdx = findOverlayByName((const char *)scriptName);
|
||||
|
||||
if (scriptIdx == -4) {
|
||||
scriptIdx = numOfLoadedOverlay;
|
||||
|
||||
newNumberOfScript++;
|
||||
|
||||
scriptNotLoadedBefore = true;
|
||||
}
|
||||
|
||||
if (overlayTable[scriptIdx].alreadyLoaded) {
|
||||
return (scriptIdx);
|
||||
}
|
||||
|
||||
overlayTable[scriptIdx].ovlData =
|
||||
(ovlDataStruct *) mallocAndZero(sizeof(ovlDataStruct));
|
||||
|
||||
if (!overlayTable[scriptIdx].ovlData)
|
||||
return (-2);
|
||||
|
||||
if (scriptName != overlayTable[scriptIdx].overlayName)
|
||||
Common::strlcpy(overlayTable[scriptIdx].overlayName, scriptName, sizeof(overlayTable[scriptIdx].overlayName));
|
||||
|
||||
overlayTable[scriptIdx].alreadyLoaded = 1;
|
||||
|
||||
numOfLoadedOverlay = newNumberOfScript;
|
||||
|
||||
overlayTable[scriptIdx].ovlData->scriptNumber = scriptIdx;
|
||||
|
||||
Common::strlcpy(fileName, scriptName, sizeof(fileName));
|
||||
Common::strlcat(fileName, ".OVL", sizeof(fileName));
|
||||
|
||||
debug(1, "Attempting to load overlay file %s...", fileName);
|
||||
|
||||
fileIdx = findFileInDisks(fileName);
|
||||
|
||||
if (fileIdx < 0) {
|
||||
warning("Unable to load overlay %s", scriptName);
|
||||
//releaseScript(scriptName);
|
||||
return (-18);
|
||||
}
|
||||
|
||||
unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2;
|
||||
|
||||
// This memory block will be later passed to a MemoryReadStream, which will dispose of it
|
||||
unpackedBuffer = (byte *)malloc(unpackedSize);
|
||||
if (!unpackedBuffer) {
|
||||
return (-2);
|
||||
}
|
||||
memset(unpackedBuffer, 0, unpackedSize);
|
||||
|
||||
if (volumePtrToFileDescriptor[fileIdx].size + 2 != unpackedSize) {
|
||||
char *pakedBuffer =
|
||||
(char *)mallocAndZero(volumePtrToFileDescriptor[fileIdx].
|
||||
size + 2);
|
||||
|
||||
loadPackedFileToMem(fileIdx, (uint8 *) pakedBuffer);
|
||||
|
||||
delphineUnpack((uint8 *)unpackedBuffer, (const uint8 *)pakedBuffer, volumePtrToFileDescriptor[fileIdx].size);
|
||||
|
||||
MemFree(pakedBuffer);
|
||||
} else {
|
||||
loadPackedFileToMem(fileIdx, (uint8 *) unpackedBuffer);
|
||||
}
|
||||
|
||||
debug(1, "OVL loading done...");
|
||||
|
||||
Common::MemoryReadStream s(unpackedBuffer, unpackedSize, DisposeAfterUse::YES);
|
||||
unpackedBuffer = nullptr;
|
||||
|
||||
ovlData = overlayTable[scriptIdx].ovlData;
|
||||
|
||||
// Skip pointers
|
||||
s.skip(60);
|
||||
|
||||
ovlData->arrayProc = nullptr;
|
||||
ovlData->ptr1 = nullptr;
|
||||
ovlData->arrayObject = nullptr;
|
||||
ovlData->arrayStates = nullptr;
|
||||
ovlData->arrayObjVar = nullptr;
|
||||
ovlData->stringTable = nullptr;
|
||||
ovlData->arraySymbGlob = nullptr;
|
||||
ovlData->arrayRelocGlob = nullptr;
|
||||
ovlData->arrayMsgRelHeader = nullptr;
|
||||
ovlData->nameVerbGlob = nullptr;
|
||||
ovlData->arrayNameObj = nullptr;
|
||||
ovlData->arrayNameRelocGlob = nullptr;
|
||||
ovlData->arrayNameSymbGlob = nullptr;
|
||||
ovlData->data4Ptr = nullptr;
|
||||
ovlData->ptr8 = nullptr;
|
||||
ovlData->numProc = s.readUint16BE();
|
||||
ovlData->numRel = s.readUint16BE();
|
||||
ovlData->numSymbGlob = s.readUint16BE();
|
||||
ovlData->numRelocGlob = s.readUint16BE();
|
||||
ovlData->numMsgRelHeader = s.readUint16BE();
|
||||
ovlData->numObj = s.readUint16BE();
|
||||
ovlData->numStrings = s.readUint16BE();
|
||||
ovlData->size8 = s.readUint16BE();
|
||||
ovlData->size9 = s.readUint16BE();
|
||||
ovlData->nameExportSize = s.readUint16BE();
|
||||
ovlData->exportNamesSize = s.readUint16BE();
|
||||
ovlData->specialString2Length = s.readUint16BE();
|
||||
ovlData->sizeOfData4 = s.readUint16BE();
|
||||
ovlData->size12 = s.readUint16BE();
|
||||
ovlData->specialString1Length = s.readUint16BE();
|
||||
ovlData->scriptNumber = s.readUint16BE();
|
||||
|
||||
if (ovlData->numSymbGlob) { // export data
|
||||
ovlData->arraySymbGlob =
|
||||
(exportEntryStruct *) mallocAndZero(ovlData->numSymbGlob * sizeof(exportEntryStruct));
|
||||
|
||||
if (!ovlData->arraySymbGlob)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->numSymbGlob; i++) {
|
||||
ovlData->arraySymbGlob[i].var0 = s.readUint16BE();
|
||||
ovlData->arraySymbGlob[i].var2 = s.readUint16BE();
|
||||
ovlData->arraySymbGlob[i].var4 = s.readUint16BE();
|
||||
ovlData->arraySymbGlob[i].idx = s.readUint16BE();
|
||||
ovlData->arraySymbGlob[i].offsetToName = s.readUint16BE();
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->exportNamesSize) { // export names
|
||||
ovlData->arrayNameSymbGlob = (char *) mallocAndZero(ovlData->exportNamesSize);
|
||||
|
||||
if (!ovlData->arrayNameSymbGlob) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s.read(ovlData->arrayNameSymbGlob, ovlData->exportNamesSize);
|
||||
}
|
||||
|
||||
if (ovlData->numRelocGlob) { // import data
|
||||
ovlData->arrayRelocGlob =
|
||||
(importDataStruct *) mallocAndZero(ovlData->numRelocGlob *
|
||||
sizeof(importDataStruct));
|
||||
|
||||
if (!ovlData->arrayRelocGlob)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->numRelocGlob; i++) {
|
||||
ovlData->arrayRelocGlob[i].var0 = s.readUint16BE();
|
||||
ovlData->arrayRelocGlob[i].var1 = s.readUint16BE();
|
||||
ovlData->arrayRelocGlob[i].linkType = s.readUint16BE();
|
||||
ovlData->arrayRelocGlob[i].linkIdx = s.readUint16BE();
|
||||
ovlData->arrayRelocGlob[i].nameOffset = s.readUint16BE();
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->nameExportSize) { // import name
|
||||
ovlData->arrayNameRelocGlob = (char *) mallocAndZero(ovlData->nameExportSize);
|
||||
|
||||
if (!ovlData->arrayNameRelocGlob) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s.read(ovlData->arrayNameRelocGlob, ovlData->nameExportSize);
|
||||
}
|
||||
|
||||
if (ovlData->numMsgRelHeader) { // link data
|
||||
assert(sizeof(linkDataStruct) == 0x22);
|
||||
|
||||
ovlData->arrayMsgRelHeader = (linkDataStruct *) mallocAndZero(ovlData->numMsgRelHeader * sizeof(linkDataStruct));
|
||||
|
||||
if (!ovlData->arrayMsgRelHeader)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->numMsgRelHeader; i++) {
|
||||
ovlData->arrayMsgRelHeader[i].type = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].id = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].offsetVerbeName = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].verbOverlay = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].verbNumber = s.readUint16BE();
|
||||
|
||||
ovlData->arrayMsgRelHeader[i].obj1Overlay = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].obj1Number = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].obj2Overlay = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].obj2Number = s.readUint16BE();
|
||||
|
||||
ovlData->arrayMsgRelHeader[i].trackX = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].trackY = s.readUint16BE();
|
||||
|
||||
ovlData->arrayMsgRelHeader[i].obj1NewState = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].obj2NewState = s.readUint16BE();
|
||||
|
||||
ovlData->arrayMsgRelHeader[i].obj1OldState = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].obj2OldState = s.readUint16BE();
|
||||
|
||||
ovlData->arrayMsgRelHeader[i].trackDirection = s.readUint16BE();
|
||||
ovlData->arrayMsgRelHeader[i].dialog = s.readUint16BE();
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->numProc) { // script
|
||||
ovlData3Struct *tempPtr;
|
||||
|
||||
ovlData->arrayProc = (ovlData3Struct *) mallocAndZero(ovlData->numProc * sizeof(ovlData3Struct));
|
||||
|
||||
if (!ovlData->arrayProc)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->numProc; i++) {
|
||||
s.skip(4);
|
||||
ovlData->arrayProc[i].dataPtr = nullptr;
|
||||
ovlData->arrayProc[i].sizeOfData = s.readUint16BE();
|
||||
ovlData->arrayProc[i].offsetToSubData3 = s.readUint16BE();
|
||||
ovlData->arrayProc[i].offsetToImportData = s.readUint16BE();
|
||||
ovlData->arrayProc[i].offsetToSubData2 = s.readUint16BE();
|
||||
ovlData->arrayProc[i].offsetToImportName = s.readUint16BE();
|
||||
ovlData->arrayProc[i].offsetToSubData5 = s.readUint16BE();
|
||||
ovlData->arrayProc[i].sysKey = s.readUint16BE();
|
||||
ovlData->arrayProc[i].var12 = s.readUint16BE();
|
||||
ovlData->arrayProc[i].numRelocGlob = s.readUint16BE();
|
||||
ovlData->arrayProc[i].subData2Size = s.readUint16BE();
|
||||
ovlData->arrayProc[i].var18 = s.readUint16BE();
|
||||
ovlData->arrayProc[i].var1A = s.readUint16BE();
|
||||
}
|
||||
|
||||
tempPtr = ovlData->arrayProc;
|
||||
|
||||
for (int i = 0; i < ovlData->numProc; i++) {
|
||||
tempPtr->dataPtr = (uint8 *) mallocAndZero(tempPtr->sizeOfData);
|
||||
|
||||
if (!tempPtr->dataPtr) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s.read(tempPtr->dataPtr, tempPtr->sizeOfData);
|
||||
|
||||
if (tempPtr->offsetToImportData) {
|
||||
flipGen(tempPtr->dataPtr + tempPtr->offsetToImportData,
|
||||
tempPtr->numRelocGlob * 10);
|
||||
}
|
||||
|
||||
if (tempPtr->offsetToSubData2) {
|
||||
flipGen(tempPtr->dataPtr + tempPtr->offsetToSubData2,
|
||||
tempPtr->subData2Size * 10);
|
||||
}
|
||||
|
||||
tempPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->numRel) {
|
||||
ovlData3Struct *tempPtr;
|
||||
|
||||
ovlData->ptr1 = (ovlData3Struct *) mallocAndZero(ovlData->numRel * sizeof(ovlData3Struct));
|
||||
|
||||
if (!ovlData->ptr1)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->numRel; i++) {
|
||||
s.skip(4);
|
||||
ovlData->ptr1[i].dataPtr = nullptr;
|
||||
ovlData->ptr1[i].sizeOfData = s.readUint16BE();
|
||||
ovlData->ptr1[i].offsetToSubData3 = s.readUint16BE();
|
||||
ovlData->ptr1[i].offsetToImportData = s.readUint16BE();
|
||||
ovlData->ptr1[i].offsetToSubData2 = s.readUint16BE();
|
||||
ovlData->ptr1[i].offsetToImportName = s.readUint16BE();
|
||||
ovlData->ptr1[i].offsetToSubData5 = s.readUint16BE();
|
||||
ovlData->ptr1[i].sysKey = s.readUint16BE();
|
||||
ovlData->ptr1[i].var12 = s.readUint16BE();
|
||||
ovlData->ptr1[i].numRelocGlob = s.readUint16BE();
|
||||
ovlData->ptr1[i].subData2Size = s.readUint16BE();
|
||||
ovlData->ptr1[i].var18 = s.readUint16BE();
|
||||
ovlData->ptr1[i].var1A = s.readUint16BE();
|
||||
}
|
||||
|
||||
tempPtr = (ovlData3Struct *) ovlData->ptr1;
|
||||
|
||||
for (int i = 0; i < ovlData->numRel; i++) {
|
||||
tempPtr->dataPtr = (uint8 *) mallocAndZero(tempPtr->sizeOfData);
|
||||
|
||||
if (!tempPtr->dataPtr)
|
||||
return (-2);
|
||||
|
||||
s.read(tempPtr->dataPtr, tempPtr->sizeOfData);
|
||||
|
||||
if (tempPtr->offsetToImportData) {
|
||||
flipGen(tempPtr->dataPtr + tempPtr->offsetToImportData,
|
||||
tempPtr->numRelocGlob * 10);
|
||||
}
|
||||
|
||||
if (tempPtr->offsetToSubData2) {
|
||||
flipGen(tempPtr->dataPtr + tempPtr->offsetToSubData2,
|
||||
tempPtr->subData2Size * 10);
|
||||
}
|
||||
|
||||
tempPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->size12) {
|
||||
ovlData->ptr8 = (uint8 *) mallocAndZero(ovlData->size12);
|
||||
|
||||
if (!ovlData->ptr8) {
|
||||
/* releaseScript(scriptIdx,scriptName);
|
||||
|
||||
if (freeIsNeeded) {
|
||||
freePtr(unpackedBuffer);
|
||||
} */
|
||||
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s.read(ovlData->ptr8, ovlData->size12);
|
||||
}
|
||||
|
||||
if (ovlData->numObj) {
|
||||
ovlData->arrayObject = (objDataStruct *) mallocAndZero(ovlData->numObj * sizeof(objDataStruct));
|
||||
|
||||
if (!ovlData->arrayObject)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->numObj; i++) {
|
||||
ovlData->arrayObject[i]._type = s.readUint16BE();
|
||||
ovlData->arrayObject[i]._class = (eClass) s.readUint16BE();
|
||||
ovlData->arrayObject[i]._nameOffset = s.readUint16BE();
|
||||
ovlData->arrayObject[i]._numStates = s.readUint16BE();
|
||||
ovlData->arrayObject[i]._varTableIdx = s.readUint16BE();
|
||||
ovlData->arrayObject[i]._firstStateIdx = s.readUint16BE();
|
||||
ovlData->arrayObject[i]._stateTableIdx = s.readUint16BE();
|
||||
}
|
||||
|
||||
// allocate states for object with multiple states
|
||||
|
||||
if (scriptNotLoadedBefore) {
|
||||
overlayTable[scriptIdx].state = stateID;
|
||||
stateID += getNumObjectsByClass(scriptIdx, MULTIPLE) + getNumObjectsByClass(scriptIdx, THEME);
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->size9) {
|
||||
ovlData->arrayObjVar =
|
||||
(objectParams *) mallocAndZero(ovlData->size9 *
|
||||
sizeof(objectParams));
|
||||
|
||||
if (!ovlData->arrayObjVar) {
|
||||
return (-2);
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->size8) {
|
||||
ovlData->arrayStates = (objectParams *) mallocAndZero(ovlData->size8 * sizeof(objectParams));
|
||||
|
||||
if (!ovlData->arrayStates)
|
||||
return (-2);
|
||||
|
||||
for (int i = 0; i < ovlData->size8; i++) {
|
||||
ovlData->arrayStates[i].X = s.readUint16BE();
|
||||
ovlData->arrayStates[i].Y = s.readUint16BE();
|
||||
ovlData->arrayStates[i].Z = s.readUint16BE();
|
||||
ovlData->arrayStates[i].frame = s.readUint16BE();
|
||||
ovlData->arrayStates[i].scale = s.readUint16BE();
|
||||
ovlData->arrayStates[i].state = s.readUint16BE();
|
||||
}
|
||||
}
|
||||
|
||||
if (ovlData->numStrings) {
|
||||
ovlData->stringTable = (stringEntryStruct *) mallocAndZero(ovlData->numStrings * sizeof(stringEntryStruct));
|
||||
|
||||
for (int i = 0; i < ovlData->numStrings; i++)
|
||||
ovlData->stringTable[i].idx = s.readUint16BE();
|
||||
}
|
||||
|
||||
if (ovlData->sizeOfData4) {
|
||||
ovlData->data4Ptr = (uint8 *) mallocAndZero(ovlData->sizeOfData4);
|
||||
|
||||
if (!ovlData->data4Ptr)
|
||||
return (-2);
|
||||
}
|
||||
|
||||
if (ovlData->specialString1Length /*|| ovlData->specialString2Length */
|
||||
|| ovlData->stringTable) {
|
||||
//int unpackedSize;
|
||||
//int fileIdx;
|
||||
//uint8 fileName[50];
|
||||
//char* unpackedBuffer;
|
||||
|
||||
Common::strlcpy(fileName, scriptName, sizeof(fileName));
|
||||
Common::strlcat(fileName, ".FR", sizeof(fileName));
|
||||
|
||||
fileIdx = findFileInDisks(fileName);
|
||||
|
||||
if (fileIdx < 0) {
|
||||
//releaseScript(scriptName);
|
||||
return (-18);
|
||||
}
|
||||
|
||||
unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2;
|
||||
|
||||
// This memory block will be later passed to a MemoryReadStream, which will dispose of it
|
||||
unpackedBuffer = (byte *)malloc(unpackedSize);
|
||||
if (!unpackedBuffer) {
|
||||
return (-2);
|
||||
}
|
||||
memset(unpackedBuffer, 0, unpackedSize);
|
||||
|
||||
if (volumePtrToFileDescriptor[fileIdx].size + 2 !=
|
||||
unpackedSize) {
|
||||
char *pakedBuffer =
|
||||
(char *)
|
||||
mallocAndZero(volumePtrToFileDescriptor[fileIdx].
|
||||
size + 2);
|
||||
|
||||
loadPackedFileToMem(fileIdx, (uint8 *) pakedBuffer);
|
||||
|
||||
delphineUnpack((uint8 *) unpackedBuffer, (const uint8 *)pakedBuffer, volumePtrToFileDescriptor[fileIdx].size);
|
||||
|
||||
MemFree(pakedBuffer);
|
||||
} else {
|
||||
loadPackedFileToMem(fileIdx, (uint8 *) unpackedBuffer);
|
||||
}
|
||||
|
||||
Common::MemoryReadStream s2(unpackedBuffer, unpackedSize, DisposeAfterUse::YES);
|
||||
unpackedBuffer = nullptr;
|
||||
|
||||
ovlData->specialString1Length = s2.readUint16BE();
|
||||
if (ovlData->specialString1Length) {
|
||||
ovlData->nameVerbGlob = (char *) mallocAndZero(ovlData->specialString1Length);
|
||||
|
||||
if (!ovlData->nameVerbGlob) {
|
||||
/* releaseScript(scriptIdx,scriptName);
|
||||
*
|
||||
* if (freeIsNeeded)
|
||||
* {
|
||||
* freePtr(unpackedBuffer);
|
||||
* } */
|
||||
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s2.read(ovlData->nameVerbGlob, ovlData->specialString1Length);
|
||||
}
|
||||
|
||||
ovlData->specialString2Length = s2.readUint16BE();
|
||||
if (ovlData->specialString2Length) {
|
||||
ovlData->arrayNameObj = (char *) mallocAndZero(ovlData->specialString2Length);
|
||||
|
||||
if (!ovlData->arrayNameObj) {
|
||||
/* releaseScript(scriptIdx,scriptName);
|
||||
*
|
||||
* if (freeIsNeeded)
|
||||
* {
|
||||
* freePtr(unpackedBuffer);
|
||||
* } */
|
||||
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s2.read(ovlData->arrayNameObj, ovlData->specialString2Length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ovlData->numStrings; i++) {
|
||||
ovlData->stringTable[i].length = s2.readUint16BE();
|
||||
|
||||
if (ovlData->stringTable[i].length) {
|
||||
ovlData->stringTable[i].string =
|
||||
(char *)mallocAndZero(ovlData->
|
||||
stringTable[i].length);
|
||||
|
||||
if (!ovlData->stringTable[i].string) {
|
||||
/* releaseScript(scriptIdx,scriptName);
|
||||
*
|
||||
* if (freeIsNeeded)
|
||||
* {
|
||||
* freePtr(unpackedBuffer);
|
||||
* } */
|
||||
|
||||
return (-2);
|
||||
}
|
||||
|
||||
s2.read(ovlData->stringTable[i].string, ovlData->stringTable[i].length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DUMP_SCRIPT
|
||||
{
|
||||
for (int i = 0; i < ovlData->numProc; i++) {
|
||||
dumpScript(scriptName, ovlData, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DUMP_OBJECT
|
||||
{
|
||||
// TODO: Rewrite this to use Common::DumpFile
|
||||
FILE *fHandle;
|
||||
char nameBundle[100];
|
||||
Common::sprintf_s(nameBundle, "%s-objs.txt", scriptName);
|
||||
|
||||
fHandle = fopen(nameBundle, "w+");
|
||||
assert(fHandle);
|
||||
|
||||
for (int i = 0; i < ovlData->numMsgRelHeader; i++) {
|
||||
linkDataStruct *var_34;
|
||||
var_34 = &ovlData->arrayMsgRelHeader[i];
|
||||
|
||||
if (ovlData->arrayNameObj) {
|
||||
fprintf(fHandle, "----- object %02d -----\n",
|
||||
i);
|
||||
if (var_34->stringNameOffset != 0xFFFF) {
|
||||
fprintf(fHandle, "name: %s\n",
|
||||
getObjectName(var_34->
|
||||
stringNameOffset,
|
||||
ovlData->arrayNameObj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (scriptIdx);
|
||||
}
|
||||
|
||||
int releaseOverlay(const char *name) {
|
||||
int overlayIdx = findOverlayByName(name);
|
||||
|
||||
if (overlayIdx == -4)
|
||||
return -4;
|
||||
|
||||
return freeOverlay(overlayIdx);
|
||||
}
|
||||
|
||||
int32 findOverlayByName2(const char *name) {
|
||||
for (int i = 1; i < numOfLoadedOverlay; i++) {
|
||||
if (!strcmp(overlayTable[i].overlayName, name))
|
||||
return (i);
|
||||
}
|
||||
|
||||
return (-4);
|
||||
}
|
||||
|
||||
int findOverlayByName(const char *overlayName) {
|
||||
for (int i = 1; i < numOfLoadedOverlay; i++) {
|
||||
if (!strcmp(overlayTable[i].overlayName, overlayName))
|
||||
return (i);
|
||||
}
|
||||
|
||||
return (-4);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
188
engines/cruise/overlay.h
Normal file
188
engines/cruise/overlay.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/* 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 CRUISE_OVERLAY_H
|
||||
#define CRUISE_OVERLAY_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct importScriptStruct {
|
||||
uint16 var0;
|
||||
uint16 var1;
|
||||
uint16 type;
|
||||
uint16 offset;
|
||||
uint16 offsetToName;
|
||||
};
|
||||
|
||||
struct exportEntryStruct {
|
||||
uint16 var0;
|
||||
uint16 var2;
|
||||
uint16 var4;
|
||||
uint16 idx;
|
||||
uint16 offsetToName;
|
||||
};
|
||||
|
||||
struct ovlData3Struct {
|
||||
uint8 *dataPtr; //0
|
||||
short int sizeOfData; //4
|
||||
short int offsetToSubData3; //6
|
||||
short int offsetToImportData; //8
|
||||
short int offsetToSubData2;
|
||||
short int offsetToImportName;
|
||||
short int offsetToSubData5;
|
||||
short int sysKey;
|
||||
short int var12;
|
||||
short int numRelocGlob;
|
||||
short int subData2Size;
|
||||
short int var18;
|
||||
short int var1A;
|
||||
};
|
||||
|
||||
struct stringEntryStruct {
|
||||
char *string;
|
||||
short int length;
|
||||
short int idx;
|
||||
};
|
||||
|
||||
struct linkDataStruct {
|
||||
int16 type;
|
||||
int16 id;
|
||||
int16 offsetVerbeName;
|
||||
int16 verbOverlay;
|
||||
int16 verbNumber;
|
||||
|
||||
int16 obj1Overlay;
|
||||
int16 obj1Number;
|
||||
int16 obj2Overlay;
|
||||
int16 obj2Number;
|
||||
|
||||
int16 trackX;
|
||||
int16 trackY;
|
||||
|
||||
int16 obj1NewState;
|
||||
int16 obj2NewState;
|
||||
|
||||
int16 obj1OldState;
|
||||
int16 obj2OldState;
|
||||
|
||||
int16 trackDirection;
|
||||
int16 dialog;
|
||||
};
|
||||
|
||||
struct importDataStruct {
|
||||
uint16 var0; // 0
|
||||
uint16 var1; // 2
|
||||
uint16 linkType; // 4
|
||||
uint16 linkIdx; // 6
|
||||
uint16 nameOffset;
|
||||
};
|
||||
|
||||
enum eClass {
|
||||
MULTIPLE = 0,
|
||||
VARIABLE = 1,
|
||||
UNIQUE = 2,
|
||||
THEME = 3
|
||||
};
|
||||
|
||||
struct objDataStruct {
|
||||
int16 _type;
|
||||
eClass _class;
|
||||
int16 _nameOffset;
|
||||
int16 _numStates;
|
||||
int16 _varTableIdx;
|
||||
int16 _firstStateIdx;
|
||||
int16 _stateTableIdx;
|
||||
};
|
||||
|
||||
struct objectParams {
|
||||
int16 X;
|
||||
int16 Y;
|
||||
int16 Z;
|
||||
int16 frame;
|
||||
int16 scale;
|
||||
int16 state;
|
||||
};
|
||||
|
||||
struct ovlDataStruct {
|
||||
|
||||
ovlData3Struct *arrayProc;
|
||||
ovlData3Struct *ptr1;
|
||||
objDataStruct *arrayObject;
|
||||
objectParams *arrayStates;
|
||||
objectParams *arrayObjVar;
|
||||
stringEntryStruct *stringTable;
|
||||
exportEntryStruct *arraySymbGlob;
|
||||
importDataStruct *arrayRelocGlob;
|
||||
linkDataStruct *arrayMsgRelHeader;
|
||||
|
||||
char *nameVerbGlob;
|
||||
char *arrayNameObj;
|
||||
char *arrayNameRelocGlob;
|
||||
char *arrayNameSymbGlob;
|
||||
|
||||
uint8 *data4Ptr;
|
||||
uint8 *ptr8;
|
||||
|
||||
unsigned short int numProc;
|
||||
unsigned short int numRel;
|
||||
unsigned short int numSymbGlob;
|
||||
unsigned short int numRelocGlob;
|
||||
unsigned short int numMsgRelHeader;
|
||||
unsigned short int numObj;
|
||||
unsigned short int numStrings;
|
||||
unsigned short int size8;
|
||||
unsigned short int size9;
|
||||
|
||||
unsigned short int nameExportSize;
|
||||
unsigned short int exportNamesSize;
|
||||
unsigned short int specialString2Length;
|
||||
unsigned short int sizeOfData4;
|
||||
unsigned short int size12;
|
||||
unsigned short int specialString1Length;
|
||||
unsigned short int scriptNumber;
|
||||
};
|
||||
|
||||
struct overlayStruct {
|
||||
char overlayName[13];
|
||||
ovlDataStruct *ovlData;
|
||||
short int alreadyLoaded;
|
||||
short int state;
|
||||
char* pDebug;
|
||||
long int debugSize;
|
||||
char* pSource;
|
||||
long int sourceSize;
|
||||
short int executeScripts;
|
||||
};
|
||||
|
||||
extern overlayStruct overlayTable[90];
|
||||
extern int numOfLoadedOverlay;
|
||||
|
||||
void initOverlayTable();
|
||||
int loadOverlay(const char * scriptName);
|
||||
int32 findOverlayByName2(const char * name);
|
||||
int findOverlayByName(const char *overlayName);
|
||||
int releaseOverlay(const char *name);
|
||||
int freeOverlay(int overlayIdx);
|
||||
void freeOverlayTable();
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
247
engines/cruise/perso.cpp
Normal file
247
engines/cruise/perso.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/* 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 "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
persoStruct *persoTable[NUM_PERSONS];
|
||||
|
||||
int16 numPoly;
|
||||
|
||||
void freePerso(int persoIdx) {
|
||||
if (persoTable[persoIdx]) {
|
||||
MemFree(persoTable[persoIdx]);
|
||||
persoTable[persoIdx] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void freeCTP() {
|
||||
|
||||
for (unsigned long int i = 0; i < NUM_PERSONS; i++) {
|
||||
freePerso(i);
|
||||
}
|
||||
|
||||
if (_vm->_polyStruct) {
|
||||
_vm->_polyStructNorm.clear();
|
||||
_vm->_polyStructExp.clear();
|
||||
_vm->_polyStruct = nullptr;
|
||||
}
|
||||
|
||||
ctpVar17 = nullptr;
|
||||
_vm->_polyStruct = nullptr;
|
||||
|
||||
currentCtpName[0] = '\0';
|
||||
}
|
||||
|
||||
int pathVar0;
|
||||
|
||||
unsigned int inc_jo;
|
||||
|
||||
int direction(int x1, int y1, int x2, int y2, int inc_jo1, int inc_jo2) {
|
||||
int h, v, h1, v1;
|
||||
|
||||
h1 = x1 - x2;
|
||||
h = ABS(h1);
|
||||
v1 = y1 - y2;
|
||||
v = ABS(v1);
|
||||
|
||||
if (v > h) {
|
||||
if (h > 30)
|
||||
inc_jo = inc_jo1 - inc_jo2;
|
||||
else
|
||||
inc_jo = inc_jo2;
|
||||
|
||||
if (v1 < 0)
|
||||
return (2);
|
||||
else
|
||||
return (0);
|
||||
} else {
|
||||
inc_jo = inc_jo1;
|
||||
|
||||
if (h1 < 0)
|
||||
return (1);
|
||||
else
|
||||
return (3);
|
||||
}
|
||||
}
|
||||
|
||||
int cor_droite(int x1, int y1, int x2, int y2, point* outputTable) {
|
||||
int numOutput = 0;
|
||||
|
||||
int dx;
|
||||
int dy;
|
||||
|
||||
int mD0;
|
||||
int mD1;
|
||||
|
||||
int mA0;
|
||||
int mA1;
|
||||
|
||||
int bp;
|
||||
int cx;
|
||||
int si;
|
||||
|
||||
int ax;
|
||||
int bx;
|
||||
|
||||
outputTable[numOutput].x = x1;
|
||||
outputTable[numOutput].y = y1;
|
||||
numOutput++;
|
||||
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
|
||||
mD0 = mD1 = 1;
|
||||
|
||||
if (dx < 0) {
|
||||
dx = -dx;
|
||||
mD0 = -1;
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
dy = -dy;
|
||||
mD1 = -1;
|
||||
}
|
||||
|
||||
if (dx < dy) {
|
||||
mA0 = 0;
|
||||
bp = dx;
|
||||
cx = dy;
|
||||
|
||||
mA1 = mD1;
|
||||
} else {
|
||||
mA1 = 0;
|
||||
bp = dy;
|
||||
cx = dx;
|
||||
|
||||
mA0 = mD0;
|
||||
}
|
||||
|
||||
bp = bp * 2;
|
||||
dx = bp - cx;
|
||||
si = dx - cx;
|
||||
|
||||
ax = x1;
|
||||
bx = y1;
|
||||
|
||||
while (--cx) {
|
||||
if (dx > 0) {
|
||||
ax += mD0;
|
||||
bx += mD1;
|
||||
dx += si;
|
||||
} else {
|
||||
ax += mA0;
|
||||
bx += mA1;
|
||||
dx += bp;
|
||||
}
|
||||
|
||||
outputTable[numOutput].x = ax;
|
||||
outputTable[numOutput].y = bx;
|
||||
numOutput++;
|
||||
|
||||
}
|
||||
|
||||
flag_obstacle = 0;
|
||||
|
||||
return numOutput;
|
||||
}
|
||||
|
||||
void processActorWalk(MovementEntry &resx_y, int16 *inc_droite, int16 *inc_droite0,
|
||||
int16 *inc_chemin, point* cor_joueur,
|
||||
int16 solution0[NUM_NODES + 3][2], int16 *inc_jo1, int16 *inc_jo2,
|
||||
int16 *dir_perso, int16 *inc_jo0, int16 num) {
|
||||
int u = 0;
|
||||
inc_jo = *inc_jo0;
|
||||
|
||||
int i = *inc_chemin;
|
||||
|
||||
if (!*inc_droite) {
|
||||
int x1 = solution0[i][0];
|
||||
int y1 = solution0[i][1];
|
||||
i++;
|
||||
if (solution0[i][0] != -1) {
|
||||
do {
|
||||
if (solution0[i][0] != -2) {
|
||||
int x2 = solution0[i][0];
|
||||
int y2 = solution0[i][1];
|
||||
if ((x1 == x2) && (y1 == y2)) {
|
||||
resx_y.x = -1;
|
||||
resx_y.y = -1;
|
||||
freePerso(num);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
*inc_droite0 = cor_droite(x1, y1, x2, y2, cor_joueur);
|
||||
*dir_perso = resx_y.direction = direction(x1, y1, x2, y2, *inc_jo1, *inc_jo2);
|
||||
*inc_jo0 = inc_jo;
|
||||
u = 1;
|
||||
} else
|
||||
i++;
|
||||
|
||||
} while (solution0[i][0] != -1 && !u);
|
||||
}
|
||||
if (!u) {
|
||||
resx_y.x = -1;
|
||||
resx_y.y = -1;
|
||||
freePerso(num);
|
||||
|
||||
return;
|
||||
}
|
||||
*inc_chemin = i;
|
||||
}
|
||||
|
||||
resx_y.x = cor_joueur[*inc_droite].x;
|
||||
resx_y.y = cor_joueur[*inc_droite].y;
|
||||
resx_y.direction = *dir_perso;
|
||||
resx_y.zoom = computeZoom(resx_y.y);
|
||||
|
||||
getPixel(resx_y.x, resx_y.y);
|
||||
resx_y.poly = numPoly;
|
||||
|
||||
u = subOp23(resx_y.zoom, inc_jo);
|
||||
if (!u)
|
||||
u = 1;
|
||||
*inc_droite += u;
|
||||
|
||||
if ((*inc_droite) >= (*inc_droite0)) {
|
||||
*inc_droite = 0;
|
||||
resx_y.x = solution0[*inc_chemin][0];
|
||||
resx_y.y = solution0[*inc_chemin][1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void affiche_chemin(int16 persoIdx, MovementEntry &data) {
|
||||
persoStruct *pPerso = persoTable[persoIdx];
|
||||
|
||||
assert(pPerso);
|
||||
|
||||
processActorWalk(data, &pPerso->inc_droite, &pPerso->inc_droite0,
|
||||
&pPerso->inc_chemin, pPerso->coordinates, pPerso->solution,
|
||||
&pPerso->inc_jo1, &pPerso->inc_jo2, &pPerso->dir_perso,
|
||||
&pPerso->inc_jo0, persoIdx);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
68
engines/cruise/perso.h
Normal file
68
engines/cruise/perso.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 CRUISE_PERSO_H
|
||||
#define CRUISE_PERSO_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
enum {
|
||||
NUM_NODES = 20,
|
||||
NUM_PERSONS = 10
|
||||
};
|
||||
|
||||
struct point {
|
||||
int16 x;
|
||||
int16 y;
|
||||
};
|
||||
|
||||
struct persoStruct {
|
||||
int16 inc_droite; // 2
|
||||
int16 inc_droite0; // 2
|
||||
int16 inc_chemin; // 2
|
||||
point coordinates[400]; // 1600
|
||||
int16 solution[NUM_NODES + 3][2]; //((20+3)*2*2)
|
||||
int16 inc_jo1; // 2
|
||||
int16 inc_jo2; // 2
|
||||
int16 dir_perso; // 2
|
||||
int16 inc_jo0; // 2
|
||||
};
|
||||
|
||||
struct MovementEntry {
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 direction;
|
||||
int16 zoom;
|
||||
int16 poly;
|
||||
};
|
||||
|
||||
extern persoStruct *persoTable[NUM_PERSONS];
|
||||
extern int16 numPoly;
|
||||
|
||||
int cor_droite(int x1, int y1, int x2, int y2, point* outputTable);
|
||||
void freePerso(int persoIdx);
|
||||
void freeCTP();
|
||||
void affiche_chemin(int16 persoIdx, MovementEntry &data);
|
||||
int direction(int x1, int y1, int x2, int y2, int inc_jo1, int inc_jo2);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
267
engines/cruise/polys.cpp
Normal file
267
engines/cruise/polys.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
typedef char ColorP;
|
||||
|
||||
#define SCREENHEIGHT 200
|
||||
#define MAXPTS 10
|
||||
#define putdot(x,y) {if ((y >= 0) && (y < SCREENHEIGHT)) dots[y][counters[y]++] = x;}
|
||||
|
||||
void hline(int x1, int x2, int y, char c) {
|
||||
for (; x1 <= x2; x1++) {
|
||||
pixel(x1, y, c);
|
||||
}
|
||||
}
|
||||
|
||||
void vline(int x, int y1, int y2, char c) {
|
||||
for (; y1 <= y2; y1++) {
|
||||
pixel(x, y1, c);
|
||||
}
|
||||
}
|
||||
|
||||
void bsubline_1(int x1, int y1, int x2, int y2, char c) {
|
||||
int x, y, ddx, ddy, e;
|
||||
ddx = ABS(x2 - x1);
|
||||
ddy = ABS(y2 - y1) << 1;
|
||||
e = ddx - ddy;
|
||||
ddx <<= 1;
|
||||
|
||||
if (x1 > x2) {
|
||||
SWAP(x1, x2);
|
||||
SWAP(y1, y2);
|
||||
}
|
||||
|
||||
for (x = x1, y = y1; x <= x2; x++) {
|
||||
|
||||
pixel(x, y, c);
|
||||
if (e < 0) {
|
||||
y++;
|
||||
e += ddx - ddy;
|
||||
} else {
|
||||
e -= ddy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void bsubline_2(int x1, int y1, int x2, int y2, char c) {
|
||||
|
||||
int x, y, ddx, ddy, e;
|
||||
ddx = ABS(x2 - x1) << 1;
|
||||
ddy = ABS(y2 - y1);
|
||||
e = ddy - ddx;
|
||||
ddy <<= 1;
|
||||
|
||||
if (y1 > y2) {
|
||||
SWAP(x1, x2);
|
||||
SWAP(y1, y2);
|
||||
}
|
||||
|
||||
for (y = y1, x = x1; y <= y2; y++) {
|
||||
|
||||
pixel(x, y, c);
|
||||
if (e < 0) {
|
||||
x++;
|
||||
e += ddy - ddx;
|
||||
} else {
|
||||
e -= ddx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void bsubline_3(int x1, int y1, int x2, int y2, char c) {
|
||||
|
||||
int x, y, ddx, ddy, e;
|
||||
|
||||
ddx = ABS(x1 - x2) << 1;
|
||||
ddy = ABS(y2 - y1);
|
||||
e = ddy - ddx;
|
||||
ddy <<= 1;
|
||||
|
||||
if (y1 > y2) {
|
||||
SWAP(x1, x2);
|
||||
SWAP(y1, y2);
|
||||
}
|
||||
|
||||
for (y = y1, x = x1; y <= y2; y++) {
|
||||
|
||||
pixel(x, y, c);
|
||||
if (e < 0) {
|
||||
x--;
|
||||
e += ddy - ddx;
|
||||
} else {
|
||||
e -= ddx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void bsubline_4(int x1, int y1, int x2, int y2, char c) {
|
||||
|
||||
int x, y, ddx, ddy, e;
|
||||
|
||||
ddy = ABS(y2 - y1) << 1;
|
||||
ddx = ABS(x1 - x2);
|
||||
e = ddx - ddy;
|
||||
ddx <<= 1;
|
||||
|
||||
if (x1 > x2) {
|
||||
SWAP(x1, x2);
|
||||
SWAP(y1, y2);
|
||||
}
|
||||
|
||||
for (x = x1, y = y1; x <= x2; x++) {
|
||||
|
||||
pixel(x, y, c);
|
||||
if (e < 0) {
|
||||
y--;
|
||||
e += ddx - ddy;
|
||||
} else {
|
||||
e -= ddy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void line(int x1, int y1, int x2, int y2, char c) {
|
||||
float k;
|
||||
|
||||
if ((x1 == x2) && (y1 == y2)) {
|
||||
pixel(x1, y1, c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (x1 == x2) {
|
||||
vline(x1, MIN(y1, y2), MAX(y1, y2), c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (y1 == y2) {
|
||||
hline(MIN(x1, x2), MAX(x1, x2), y1, c);
|
||||
return;
|
||||
}
|
||||
|
||||
k = (float)(y2 - y1) / (float)(x2 - x1);
|
||||
|
||||
if ((k >= 0) && (k <= 1)) {
|
||||
bsubline_1(x1, y1, x2, y2, c);
|
||||
} else if (k > 1) {
|
||||
bsubline_2(x1, y1, x2, y2, c);
|
||||
} else if ((k < 0) && (k >= -1)) {
|
||||
bsubline_4(x1, y1, x2, y2, c);
|
||||
} else {
|
||||
bsubline_3(x1, y1, x2, y2, c);
|
||||
}
|
||||
}
|
||||
|
||||
// Filled polygons. This probably isn't pixel-perfect compared to the original,
|
||||
// but it seems to work a bit better than the previous version.
|
||||
|
||||
static void add_intersect(int *intersect, int x, byte &num) {
|
||||
if (num < MAXPTS) {
|
||||
|
||||
int i = 0;
|
||||
for (i = num; i > 0 && intersect[i - 1] > x; i--)
|
||||
intersect[i] = intersect[i - 1];
|
||||
|
||||
intersect[i] = x;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
void fillpoly(int16 *point_data, int lineCount, ColorP color) {
|
||||
static int intersect[SCREENHEIGHT][MAXPTS];
|
||||
static byte num_intersect[SCREENHEIGHT];
|
||||
|
||||
switch (lineCount) {
|
||||
case 0: // do nothing
|
||||
return;
|
||||
case 1: // draw pixel
|
||||
pixel(point_data[0], point_data[1], color);
|
||||
return;
|
||||
case 2: // draw line
|
||||
line(point_data[0], point_data[1], point_data[2], point_data[3], color);
|
||||
return;
|
||||
default: // go on and draw polygon
|
||||
break;
|
||||
}
|
||||
|
||||
// Reinit array counters
|
||||
for (int i = 0; i < SCREENHEIGHT; i++) {
|
||||
num_intersect[i] = 0;
|
||||
}
|
||||
|
||||
// Find the top/bottom of the polygon.
|
||||
int top = point_data[1];
|
||||
int bottom = point_data[1];
|
||||
|
||||
for (int i = 1; i < lineCount; i++) {
|
||||
if (point_data[2 * i + 1] < top)
|
||||
top = point_data[2 * i + 1];
|
||||
else if (point_data[2 * i + 1] > bottom)
|
||||
bottom = point_data[2 * i + 1];
|
||||
}
|
||||
|
||||
if (top < 0)
|
||||
top = 0;
|
||||
if (bottom >= SCREENHEIGHT)
|
||||
bottom = SCREENHEIGHT - 1;
|
||||
|
||||
// Calculate intersections for each scan line
|
||||
for (int y = top; y <= bottom; y++) {
|
||||
int x2 = point_data[2 * lineCount - 2];
|
||||
int y2 = point_data[2 * lineCount - 1];
|
||||
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
int x1 = x2;
|
||||
int y1 = y2;
|
||||
x2 = point_data[2 * i];
|
||||
y2 = point_data[2 * i + 1];
|
||||
|
||||
// Test if the line intersects the scan line
|
||||
|
||||
if ((y < y1) != (y < y2)) {
|
||||
if (y1 == y2) {
|
||||
add_intersect(intersect[y], x1, num_intersect[y]);
|
||||
add_intersect(intersect[y], x2, num_intersect[y]);
|
||||
} else if (x1 == x2) {
|
||||
add_intersect(intersect[y], x1, num_intersect[y]);
|
||||
} else {
|
||||
add_intersect(intersect[y], x1 + ((y - y1) * (x2 - x1)) / (y2 - y1), num_intersect[y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drawing.
|
||||
for (int y = top; y <= bottom; y++) {
|
||||
for (int i = 0; i < num_intersect[y]; i += 2) {
|
||||
hline(intersect[y][i], intersect[y][i + 1], y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
34
engines/cruise/polys.h
Normal file
34
engines/cruise/polys.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* 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 CRUISE_POLYS_H
|
||||
#define CRUISE_POLYS_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
typedef char ColorP;
|
||||
|
||||
void fillpoly(int16 *point_data, int n, ColorP c);
|
||||
void line(int x1, int y1, int x2, int y2, ColorP color);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
957
engines/cruise/saveload.cpp
Normal file
957
engines/cruise/saveload.cpp
Normal file
@@ -0,0 +1,957 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/vars.h"
|
||||
|
||||
#include "common/serializer.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "graphics/scaler.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
struct overlayRestoreTemporary {
|
||||
int _sBssSize;
|
||||
uint8* _pBss;
|
||||
int _sNumObj;
|
||||
objectParams* _pObj;
|
||||
};
|
||||
|
||||
overlayRestoreTemporary ovlRestoreData[90];
|
||||
|
||||
WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header, bool skipThumbnail) {
|
||||
char saveIdentBuffer[6];
|
||||
|
||||
// Validate the header Id
|
||||
in->read(saveIdentBuffer, 6);
|
||||
if (strcmp(saveIdentBuffer, "SVMCR"))
|
||||
return false;
|
||||
|
||||
header.version = in->readByte();
|
||||
if (header.version != CRUISE_SAVEGAME_VERSION)
|
||||
return false;
|
||||
|
||||
// Read in the string
|
||||
header.saveName.clear();
|
||||
char ch;
|
||||
while ((ch = (char)in->readByte()) != '\0') header.saveName += ch;
|
||||
|
||||
// Get the thumbnail
|
||||
header.thumbnail = nullptr;
|
||||
if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void writeSavegameHeader(Common::OutSaveFile *out, CruiseSavegameHeader &header) {
|
||||
// Write out a savegame header
|
||||
char saveIdentBuffer[6];
|
||||
Common::strcpy_s(saveIdentBuffer, "SVMCR");
|
||||
out->write(saveIdentBuffer, 6);
|
||||
|
||||
out->writeByte(CRUISE_SAVEGAME_VERSION);
|
||||
|
||||
// Write savegame name
|
||||
out->write(header.saveName.c_str(), header.saveName.size() + 1);
|
||||
|
||||
// Create a thumbnail and save it
|
||||
Graphics::Surface *thumb = new Graphics::Surface();
|
||||
::createThumbnail(thumb, globalScreen, 320, 200, workpal);
|
||||
Graphics::saveThumbnail(*out, *thumb);
|
||||
thumb->free();
|
||||
delete thumb;
|
||||
}
|
||||
|
||||
static void syncPalette(Common::Serializer &s, uint8 *p) {
|
||||
// This is different from the original, where palette entries are 2 bytes each
|
||||
s.syncBytes(p, NBCOLORS * 3);
|
||||
}
|
||||
|
||||
static void syncBasicInfo(Common::Serializer &s) {
|
||||
s.syncAsSint16LE(activeMouse);
|
||||
s.syncAsSint16LE(userEnabled);
|
||||
s.syncAsSint16LE(dialogueEnabled);
|
||||
s.syncAsSint16LE(dialogueOvl);
|
||||
s.syncAsSint16LE(dialogueObj);
|
||||
s.syncAsSint16LE(userDelay);
|
||||
s.syncAsSint16LE(sysKey);
|
||||
s.syncAsSint16LE(sysX);
|
||||
s.syncAsSint16LE(sysY);
|
||||
s.syncAsSint16LE(automoveInc);
|
||||
s.syncAsSint16LE(automoveMax);
|
||||
s.syncAsSint16LE(displayOn);
|
||||
s.syncAsSint16LE(isMessage);
|
||||
s.syncAsSint16LE(fadeFlag);
|
||||
s.syncAsSint16LE(automaticMode);
|
||||
s.syncAsSint16LE(titleColor);
|
||||
s.syncAsSint16LE(itemColor);
|
||||
s.syncAsSint16LE(selectColor);
|
||||
s.syncAsSint16LE(subColor);
|
||||
s.syncAsSint16LE(narratorOvl);
|
||||
s.syncAsSint16LE(narratorIdx);
|
||||
s.syncAsSint16LE(aniX);
|
||||
s.syncAsSint16LE(aniY);
|
||||
s.syncAsUint16LE(animationStart);
|
||||
s.syncAsSint16LE(masterScreen);
|
||||
s.syncAsSint16LE(switchPal);
|
||||
s.syncAsSint16LE(scroll);
|
||||
s.syncAsSint16LE(fadeFlag);
|
||||
s.syncAsSint16LE(doFade);
|
||||
s.syncAsSint16LE(numOfLoadedOverlay);
|
||||
s.syncAsSint16LE(stateID);
|
||||
s.syncAsSint16LE(fontFileIndex);
|
||||
s.syncAsSint16LE(currentActiveMenu);
|
||||
s.syncAsSint16LE(userWait);
|
||||
s.syncAsSint16LE(autoOvl);
|
||||
s.syncAsSint16LE(autoMsg);
|
||||
s.syncAsSint16LE(autoTrack);
|
||||
s.syncAsSint16LE(var39);
|
||||
s.syncAsSint16LE(var42);
|
||||
s.syncAsSint16LE(var45);
|
||||
s.syncAsSint16LE(var46);
|
||||
s.syncAsSint16LE(var47);
|
||||
s.syncAsSint16LE(var48);
|
||||
s.syncAsSint16LE(flagCt);
|
||||
s.syncAsSint16LE(var41);
|
||||
s.syncAsSint16LE(playerMenuEnabled);
|
||||
s.syncAsSint16LE(protectionCode);
|
||||
}
|
||||
|
||||
static void syncBackgroundTable(Common::Serializer &s) {
|
||||
// restore backgroundTable
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (s.isSaving() && (strlen(backgroundTable[i].name) > 8))
|
||||
warning("Saving a background resource that has too long a name");
|
||||
|
||||
s.syncBytes((byte *)backgroundTable[i].name, 9);
|
||||
s.syncBytes((byte *)backgroundTable[i].extension, 6);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncPalScreen(Common::Serializer &s) {
|
||||
for (int i = 0; i < NBSCREENS; ++i) {
|
||||
for (int j = 0; j < NBCOLORS; ++j)
|
||||
s.syncAsUint16LE(palScreen[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncSoundList(Common::Serializer &s) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
SoundEntry &se = soundList[i];
|
||||
s.syncAsSint16LE(se.frameNum);
|
||||
s.syncAsUint16LE(se.frequency);
|
||||
s.syncAsSint16LE(se.volume);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncFilesDatabase(Common::Serializer &s) {
|
||||
uint8 dummyVal = 0;
|
||||
uint32 tmp;
|
||||
|
||||
for (int i = 0; i < NUM_FILE_ENTRIES; i++) {
|
||||
dataFileEntry &fe = filesDatabase[i];
|
||||
|
||||
s.syncAsUint16LE(fe.widthInColumn);
|
||||
s.syncAsUint16LE(fe.width);
|
||||
s.syncAsUint16LE(fe.resType);
|
||||
s.syncAsUint16LE(fe.height);
|
||||
|
||||
// Remember whether this file database was open or not.
|
||||
// Upon loading, loadSavegameData uses this information
|
||||
// in order to re-open the file databases accordingly.
|
||||
tmp = (fe.subData.ptr) ? 1 : 0;
|
||||
s.syncAsUint32LE(tmp);
|
||||
if (s.isLoading()) {
|
||||
fe.subData.ptr = tmp ? (uint8 *)1 : nullptr;
|
||||
}
|
||||
|
||||
s.syncAsSint16LE(fe.subData.index);
|
||||
s.syncBytes((byte *)fe.subData.name, 13);
|
||||
s.syncAsByte(dummyVal);
|
||||
|
||||
s.syncAsSint16LE(fe.subData.transparency);
|
||||
|
||||
// Treat fe.subData.ptrMask the same as fe.subData.ptr.
|
||||
tmp = (fe.subData.ptrMask) ? 1 : 0;
|
||||
s.syncAsUint32LE(tmp);
|
||||
if (s.isLoading()) {
|
||||
fe.subData.ptrMask = tmp ? (uint8 *)1 : nullptr;
|
||||
}
|
||||
|
||||
s.syncAsUint16LE(fe.subData.resourceType);
|
||||
s.syncAsSint16LE(fe.subData.compression);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncPreloadData(Common::Serializer &s) {
|
||||
uint8 dummyByte = 0;
|
||||
uint32 dummyLong = 0;
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
preloadStruct &pe = preloadData[i];
|
||||
|
||||
s.syncBytes((byte *)pe.name, 15);
|
||||
s.syncAsByte(dummyByte);
|
||||
s.syncAsUint32LE(pe.size);
|
||||
s.syncAsUint32LE(pe.sourceSize);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsUint16LE(pe.nofree);
|
||||
s.syncAsUint16LE(pe.protect);
|
||||
s.syncAsUint16LE(pe.ovl);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncOverlays1(Common::Serializer &s) {
|
||||
uint8 dummyByte = 0;
|
||||
uint32 dummyLong = 0;
|
||||
|
||||
for (int i = 0; i < numOfLoadedOverlay; i++) {
|
||||
overlayStruct &oe = overlayTable[i];
|
||||
|
||||
s.syncBytes((byte *)oe.overlayName, 13);
|
||||
s.syncAsByte(dummyByte);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsUint16LE(oe.alreadyLoaded);
|
||||
s.syncAsUint16LE(oe.state);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsUint16LE(oe.executeScripts);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncOverlays2(Common::Serializer &s) {
|
||||
|
||||
for (int i = 1; i < numOfLoadedOverlay; i++) {
|
||||
|
||||
if (s.isSaving()) {
|
||||
// Saving code
|
||||
if (!overlayTable[i].alreadyLoaded)
|
||||
continue;
|
||||
|
||||
ovlDataStruct *ovlData = overlayTable[i].ovlData;
|
||||
|
||||
// save BSS
|
||||
s.syncAsSint16LE(ovlData->sizeOfData4);
|
||||
if (ovlData->sizeOfData4)
|
||||
s.syncBytes(ovlData->data4Ptr, ovlData->sizeOfData4);
|
||||
|
||||
// save variables
|
||||
s.syncAsSint16LE(ovlData->size9);
|
||||
for (int j = 0; j < ovlData->size9; j++) {
|
||||
s.syncAsSint16LE(ovlData->arrayObjVar[j].X);
|
||||
s.syncAsSint16LE(ovlData->arrayObjVar[j].Y);
|
||||
s.syncAsSint16LE(ovlData->arrayObjVar[j].Z);
|
||||
s.syncAsSint16LE(ovlData->arrayObjVar[j].frame);
|
||||
s.syncAsSint16LE(ovlData->arrayObjVar[j].scale);
|
||||
s.syncAsSint16LE(ovlData->arrayObjVar[j].state);
|
||||
}
|
||||
} else {
|
||||
// Loading code
|
||||
ovlRestoreData[i]._sBssSize = ovlRestoreData[i]._sNumObj = 0;
|
||||
ovlRestoreData[i]._pBss = nullptr;
|
||||
ovlRestoreData[i]._pObj = nullptr;
|
||||
|
||||
if (overlayTable[i].alreadyLoaded) {
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._sBssSize);
|
||||
|
||||
if (ovlRestoreData[i]._sBssSize) {
|
||||
ovlRestoreData[i]._pBss = (uint8 *) mallocAndZero(ovlRestoreData[i]._sBssSize);
|
||||
assert(ovlRestoreData[i]._pBss);
|
||||
|
||||
s.syncBytes(ovlRestoreData[i]._pBss, ovlRestoreData[i]._sBssSize);
|
||||
}
|
||||
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._sNumObj);
|
||||
|
||||
if (ovlRestoreData[i]._sNumObj) {
|
||||
ovlRestoreData[i]._pObj = (objectParams *) mallocAndZero(ovlRestoreData[i]._sNumObj * sizeof(objectParams));
|
||||
assert(ovlRestoreData[i]._pObj);
|
||||
|
||||
for (int j = 0; j < ovlRestoreData[i]._sNumObj; j++) {
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].X);
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].Y);
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].Z);
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].frame);
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].scale);
|
||||
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void syncScript(Common::Serializer &s, scriptInstanceStruct *entry) {
|
||||
int numScripts = 0;
|
||||
uint32 dummyLong = 0;
|
||||
uint16 dummyWord = 0;
|
||||
|
||||
if (s.isSaving()) {
|
||||
// Figure out the number of scripts to save
|
||||
scriptInstanceStruct* pCurrent = entry->nextScriptPtr;
|
||||
while (pCurrent) {
|
||||
++numScripts;
|
||||
pCurrent = pCurrent->nextScriptPtr;
|
||||
}
|
||||
}
|
||||
s.syncAsSint16LE(numScripts);
|
||||
|
||||
scriptInstanceStruct *ptr = entry->nextScriptPtr;
|
||||
for (int i = 0; i < numScripts; ++i) {
|
||||
if (s.isLoading())
|
||||
ptr = (scriptInstanceStruct *)mallocAndZero(sizeof(scriptInstanceStruct));
|
||||
|
||||
s.syncAsUint16LE(dummyWord);
|
||||
s.syncAsSint16LE(ptr->ccr);
|
||||
s.syncAsSint16LE(ptr->scriptOffset);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsSint16LE(ptr->dataSize);
|
||||
s.syncAsSint16LE(ptr->scriptNumber);
|
||||
s.syncAsSint16LE(ptr->overlayNumber);
|
||||
s.syncAsSint16LE(ptr->sysKey);
|
||||
s.syncAsSint16LE(ptr->freeze);
|
||||
s.syncAsSint16LE(ptr->type);
|
||||
s.syncAsSint16LE(ptr->var16);
|
||||
s.syncAsSint16LE(ptr->var18);
|
||||
s.syncAsSint16LE(ptr->var1A);
|
||||
|
||||
s.syncAsSint16LE(ptr->dataSize);
|
||||
|
||||
if (ptr->dataSize) {
|
||||
if (s.isLoading())
|
||||
ptr->data = (byte *)mallocAndZero(ptr->dataSize);
|
||||
s.syncBytes(ptr->data, ptr->dataSize);
|
||||
}
|
||||
|
||||
if (s.isLoading()) {
|
||||
ptr->nextScriptPtr = nullptr;
|
||||
entry->nextScriptPtr = ptr;
|
||||
entry = ptr;
|
||||
} else {
|
||||
ptr = ptr->nextScriptPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void syncCell(Common::Serializer &s) {
|
||||
int chunkCount = 0;
|
||||
cellStruct *t, *p;
|
||||
uint16 dummyWord = 0;
|
||||
|
||||
if (s.isSaving()) {
|
||||
// Figure out the number of chunks to save
|
||||
t = cellHead.next;
|
||||
while (t) {
|
||||
++chunkCount;
|
||||
t = t->next;
|
||||
}
|
||||
} else {
|
||||
cellHead.next = nullptr; // Not in ASM code, but I guess the variable is defaulted in the EXE
|
||||
}
|
||||
s.syncAsSint16LE(chunkCount);
|
||||
|
||||
t = s.isSaving() ? cellHead.next : &cellHead;
|
||||
for (int i = 0; i < chunkCount; ++i) {
|
||||
p = s.isSaving() ? t : (cellStruct *)mallocAndZero(sizeof(cellStruct));
|
||||
|
||||
s.syncAsUint16LE(dummyWord);
|
||||
s.syncAsUint16LE(dummyWord);
|
||||
|
||||
s.syncAsSint16LE(p->idx);
|
||||
s.syncAsSint16LE(p->type);
|
||||
s.syncAsSint16LE(p->overlay);
|
||||
s.syncAsSint16LE(p->x);
|
||||
s.syncAsSint16LE(p->field_C);
|
||||
s.syncAsSint16LE(p->spriteIdx);
|
||||
s.syncAsSint16LE(p->color);
|
||||
s.syncAsSint16LE(p->backgroundPlane);
|
||||
s.syncAsSint16LE(p->freeze);
|
||||
s.syncAsSint16LE(p->parent);
|
||||
s.syncAsSint16LE(p->parentOverlay);
|
||||
s.syncAsSint16LE(p->parentType);
|
||||
s.syncAsSint16LE(p->followObjectOverlayIdx);
|
||||
s.syncAsSint16LE(p->followObjectIdx);
|
||||
s.syncAsSint16LE(p->animStart);
|
||||
s.syncAsSint16LE(p->animEnd);
|
||||
s.syncAsSint16LE(p->animWait);
|
||||
s.syncAsSint16LE(p->animStep);
|
||||
s.syncAsSint16LE(p->animChange);
|
||||
s.syncAsSint16LE(p->animType);
|
||||
s.syncAsSint16LE(p->animSignal);
|
||||
s.syncAsSint16LE(p->animCounter);
|
||||
s.syncAsSint16LE(p->animLoop);
|
||||
s.syncAsUint16LE(dummyWord);
|
||||
|
||||
if (s.isSaving())
|
||||
t = t->next;
|
||||
else {
|
||||
p->next = nullptr;
|
||||
t->next = p;
|
||||
p->prev = cellHead.prev;
|
||||
cellHead.prev = p;
|
||||
t = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void syncIncrust(Common::Serializer &s) {
|
||||
int numEntries = 0;
|
||||
backgroundIncrustStruct *pl, *pl1;
|
||||
uint8 dummyByte = 0;
|
||||
uint16 dummyWord = 0;
|
||||
uint32 dummyLong = 0;
|
||||
|
||||
if (s.isSaving()) {
|
||||
// Figure out the number of entries to save
|
||||
pl = backgroundIncrustHead.next;
|
||||
while (pl) {
|
||||
++numEntries;
|
||||
pl = pl->next;
|
||||
}
|
||||
}
|
||||
s.syncAsSint16LE(numEntries);
|
||||
|
||||
pl = s.isSaving() ? backgroundIncrustHead.next : &backgroundIncrustHead;
|
||||
pl1 = &backgroundIncrustHead;
|
||||
|
||||
for (int i = 0; i < numEntries; ++i) {
|
||||
backgroundIncrustStruct *t = s.isSaving() ? pl :
|
||||
(backgroundIncrustStruct *)mallocAndZero(sizeof(backgroundIncrustStruct));
|
||||
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
|
||||
s.syncAsSint16LE(t->objectIdx);
|
||||
s.syncAsSint16LE(t->type);
|
||||
s.syncAsSint16LE(t->overlayIdx);
|
||||
s.syncAsSint16LE(t->X);
|
||||
s.syncAsSint16LE(t->Y);
|
||||
s.syncAsSint16LE(t->frame);
|
||||
s.syncAsSint16LE(t->scale);
|
||||
s.syncAsSint16LE(t->backgroundIdx);
|
||||
s.syncAsSint16LE(t->scriptNumber);
|
||||
s.syncAsSint16LE(t->scriptOverlayIdx);
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsSint16LE(t->saveWidth);
|
||||
s.syncAsSint16LE(t->saveHeight);
|
||||
s.syncAsSint16LE(t->saveSize);
|
||||
s.syncAsSint16LE(t->savedX);
|
||||
s.syncAsSint16LE(t->savedY);
|
||||
s.syncBytes((byte *)t->name, 13);
|
||||
s.syncAsByte(dummyByte);
|
||||
s.syncAsSint16LE(t->spriteId);
|
||||
s.syncAsUint16LE(dummyWord);
|
||||
|
||||
if (t->saveSize) {
|
||||
if (s.isLoading())
|
||||
t->ptr = (byte *)MemAlloc(t->saveSize);
|
||||
|
||||
s.syncBytes(t->ptr, t->saveSize);
|
||||
}
|
||||
|
||||
if (s.isSaving())
|
||||
pl = pl->next;
|
||||
else {
|
||||
t->next = nullptr;
|
||||
pl->next = t;
|
||||
t->prev = pl1->prev;
|
||||
pl1->prev = t;
|
||||
pl = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void syncActors(Common::Serializer &s) {
|
||||
int numEntries = 0;
|
||||
actorStruct *ptr;
|
||||
uint16 dummyLong = 0;
|
||||
|
||||
if (s.isSaving()) {
|
||||
ptr = actorHead.next;
|
||||
while (ptr) {
|
||||
++numEntries;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
s.syncAsSint16LE(numEntries);
|
||||
|
||||
ptr = s.isSaving() ? actorHead.next : &actorHead;
|
||||
for (int i = 0; i < numEntries; ++i) {
|
||||
actorStruct *p = s.isSaving() ? ptr : (actorStruct *)mallocAndZero(sizeof(actorStruct));
|
||||
|
||||
s.syncAsUint32LE(dummyLong);
|
||||
s.syncAsSint16LE(p->idx);
|
||||
s.syncAsSint16LE(p->type);
|
||||
s.syncAsSint16LE(p->overlayNumber);
|
||||
s.syncAsSint16LE(p->x_dest);
|
||||
s.syncAsSint16LE(p->y_dest);
|
||||
s.syncAsSint16LE(p->x);
|
||||
s.syncAsSint16LE(p->y);
|
||||
s.syncAsSint16LE(p->startDirection);
|
||||
s.syncAsSint16LE(p->nextDirection);
|
||||
s.syncAsSint16LE(p->endDirection);
|
||||
s.syncAsSint16LE(p->stepX);
|
||||
s.syncAsSint16LE(p->stepY);
|
||||
s.syncAsSint16LE(p->pathId);
|
||||
s.syncAsSint16LE(p->phase);
|
||||
s.syncAsSint16LE(p->counter);
|
||||
s.syncAsSint16LE(p->poly);
|
||||
s.syncAsSint16LE(p->flag);
|
||||
s.syncAsSint16LE(p->start);
|
||||
s.syncAsSint16LE(p->freeze);
|
||||
|
||||
if (s.isSaving())
|
||||
ptr = ptr->next;
|
||||
else {
|
||||
p->next = nullptr;
|
||||
ptr->next = p;
|
||||
p->prev = actorHead.prev;
|
||||
actorHead.prev = p;
|
||||
ptr = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void syncSongs(Common::Serializer &s) {
|
||||
int size = 0;
|
||||
|
||||
if (songLoaded) {
|
||||
// TODO: implement
|
||||
s.syncAsByte(size);
|
||||
if (s.isLoading()) {
|
||||
saveVar1 = size;
|
||||
if (saveVar1)
|
||||
s.syncBytes(saveVar2, saveVar1);
|
||||
}
|
||||
} else {
|
||||
s.syncAsByte(size);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncPerso(Common::Serializer &s, persoStruct &p) {
|
||||
s.syncAsSint16LE(p.inc_droite);
|
||||
s.syncAsSint16LE(p.inc_droite0);
|
||||
s.syncAsSint16LE(p.inc_chemin);
|
||||
|
||||
for (int i = 0; i < 400; ++i) {
|
||||
s.syncAsSint16LE(p.coordinates[i].x);
|
||||
s.syncAsSint16LE(p.coordinates[i].y);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_NODES + 3; ++i) {
|
||||
s.syncAsSint16LE(p.solution[i][0]);
|
||||
s.syncAsSint16LE(p.solution[i][1]);
|
||||
}
|
||||
|
||||
s.syncAsSint16LE(p.inc_jo1);
|
||||
s.syncAsSint16LE(p.inc_jo2);
|
||||
s.syncAsSint16LE(p.dir_perso);
|
||||
s.syncAsSint16LE(p.inc_jo0);
|
||||
}
|
||||
|
||||
static void syncCT(Common::Serializer &s) {
|
||||
int v = (_vm->_polyStruct) ? 1 : 0;
|
||||
s.syncAsSint32LE(v);
|
||||
if (s.isLoading())
|
||||
_vm->_polyStruct = (v != 0) ? &_vm->_polyStructNorm : nullptr;
|
||||
|
||||
if (v == 0)
|
||||
// There is no further data to load or save
|
||||
return;
|
||||
|
||||
s.syncAsSint16LE(numberOfWalkboxes);
|
||||
|
||||
if (numberOfWalkboxes) {
|
||||
for (int i = 0; i < numberOfWalkboxes; ++i)
|
||||
s.syncAsSint16LE(walkboxColor[i]);
|
||||
for (int i = 0; i < numberOfWalkboxes; ++i)
|
||||
s.syncAsSint16LE(walkboxState[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
v = 0;
|
||||
if (s.isSaving()) v = (persoTable[i]) ? 1 : 0;
|
||||
s.syncAsSint32LE(v);
|
||||
|
||||
if (s.isLoading())
|
||||
// Set up the pointer for the next structure
|
||||
persoTable[i] = (v == 0) ? nullptr : (persoStruct *)mallocAndZero(sizeof(persoStruct));
|
||||
|
||||
if (v != 0)
|
||||
syncPerso(s, *persoTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void DoSync(Common::Serializer &s) {
|
||||
syncBasicInfo(s);
|
||||
_vm->sound().doSync(s);
|
||||
|
||||
syncPalette(s, newPal);
|
||||
syncPalette(s, workpal);
|
||||
|
||||
s.syncBytes((byte *)currentCtpName, 40);
|
||||
|
||||
syncBackgroundTable(s);
|
||||
syncPalScreen(s);
|
||||
syncSoundList(s);
|
||||
|
||||
for (int i = 0; i < stateID; ++i)
|
||||
s.syncAsSint16LE(globalVars[i]);
|
||||
|
||||
syncFilesDatabase(s);
|
||||
syncOverlays1(s);
|
||||
syncPreloadData(s);
|
||||
syncOverlays2(s);
|
||||
syncScript(s, &procHead);
|
||||
syncScript(s, &relHead);
|
||||
syncCell(s);
|
||||
syncIncrust(s);
|
||||
syncActors(s);
|
||||
syncSongs(s);
|
||||
syncCT(s);
|
||||
}
|
||||
|
||||
|
||||
void resetPreload() {
|
||||
for (unsigned long int i = 0; i < 64; i++) {
|
||||
if (strlen(preloadData[i].name)) {
|
||||
if (preloadData[i].ptr) {
|
||||
MemFree(preloadData[i].ptr);
|
||||
preloadData[i].ptr = nullptr;
|
||||
}
|
||||
preloadData[i].name[0] = '\0';
|
||||
preloadData[i].nofree = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unloadOverlay(const char*name, int overlayNumber) {
|
||||
releaseOverlay(name);
|
||||
|
||||
overlayTable[overlayNumber].overlayName[0] = '\0';
|
||||
overlayTable[overlayNumber].ovlData = nullptr;
|
||||
overlayTable[overlayNumber].alreadyLoaded = 0;
|
||||
}
|
||||
|
||||
void initVars() {
|
||||
closeAllMenu();
|
||||
resetFileEntryRange(0, NUM_FILE_ENTRIES);
|
||||
|
||||
resetPreload();
|
||||
freeCTP();
|
||||
freeBackgroundIncrustList(&backgroundIncrustHead);
|
||||
|
||||
freezeCell(&cellHead, -1, -1, -1, -1, -1, 0);
|
||||
// TODO: unfreeze anims
|
||||
|
||||
freeObjectList(&cellHead);
|
||||
removeAnimation(&actorHead, -1, -1, -1);
|
||||
|
||||
removeAllScripts(&relHead);
|
||||
removeAllScripts(&procHead);
|
||||
changeScriptParamInList(-1, -1, &procHead, -1, 0);
|
||||
removeFinishedScripts(&procHead);
|
||||
|
||||
changeScriptParamInList(-1, -1, &relHead, -1, 0);
|
||||
removeFinishedScripts(&relHead);
|
||||
|
||||
for (unsigned long int i = 0; i < 90; i++) {
|
||||
if (strlen(overlayTable[i].overlayName) && overlayTable[i].alreadyLoaded) {
|
||||
unloadOverlay(overlayTable[i].overlayName, i);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// stopSound();
|
||||
// removeSound();
|
||||
|
||||
closeBase();
|
||||
closeCnf();
|
||||
|
||||
initOverlayTable();
|
||||
|
||||
stateID = 0;
|
||||
masterScreen = 0;
|
||||
|
||||
freeDisk();
|
||||
|
||||
soundList[0].frameNum = -1;
|
||||
soundList[1].frameNum = -1;
|
||||
soundList[2].frameNum = -1;
|
||||
soundList[3].frameNum = -1;
|
||||
|
||||
for (unsigned long int i = 0; i < 8; i++) {
|
||||
menuTable[i] = nullptr;
|
||||
}
|
||||
|
||||
for (unsigned long int i = 0; i < 2000; i++) {
|
||||
globalVars[i] = 0;
|
||||
}
|
||||
|
||||
for (unsigned long int i = 0; i < 8; i++) {
|
||||
backgroundTable[i].name[0] = 0;
|
||||
}
|
||||
|
||||
for (unsigned long int i = 0; i < NUM_FILE_ENTRIES; i++) {
|
||||
filesDatabase[i].subData.ptr = nullptr;
|
||||
filesDatabase[i].subData.ptrMask = nullptr;
|
||||
}
|
||||
|
||||
initBigVar3();
|
||||
|
||||
resetPtr2(&procHead);
|
||||
resetPtr2(&relHead);
|
||||
|
||||
resetPtr(&cellHead);
|
||||
|
||||
resetActorPtr(&actorHead);
|
||||
resetBackgroundIncrustList(&backgroundIncrustHead);
|
||||
|
||||
vblLimit = 0;
|
||||
remdo = false;
|
||||
songLoaded = 0;
|
||||
songPlayed = 0;
|
||||
songLoop = 1;
|
||||
activeMouse = 0;
|
||||
userEnabled = 1;
|
||||
dialogueEnabled = 0;
|
||||
dialogueOvl = 0;
|
||||
dialogueObj = 0;
|
||||
userDelay = 0;
|
||||
sysKey = -1;
|
||||
sysX = 0;
|
||||
sysY = 0;
|
||||
automoveInc = 0;
|
||||
automoveMax = 0;
|
||||
displayOn = true;
|
||||
|
||||
// here used to init clip
|
||||
|
||||
isMessage = 0;
|
||||
fadeFlag = 0;
|
||||
automaticMode = 0;
|
||||
|
||||
// video param (vga and mcga mode)
|
||||
|
||||
titleColor = 2;
|
||||
itemColor = 1;
|
||||
selectColor = 3;
|
||||
subColor = 5;
|
||||
|
||||
//
|
||||
|
||||
narratorOvl = 0;
|
||||
narratorIdx = 0;
|
||||
aniX = 0;
|
||||
aniY = 0;
|
||||
animationStart = false;
|
||||
selectDown = 0;
|
||||
menuDown = 0;
|
||||
buttonDown = 0;
|
||||
var41 = 0;
|
||||
playerMenuEnabled = 0;
|
||||
PCFadeFlag = false;
|
||||
}
|
||||
|
||||
Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName) {
|
||||
const char *filename = _vm->getSavegameFile(saveGameIdx);
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::OutSaveFile *f = saveMan->openForSaving(filename);
|
||||
if (f == nullptr)
|
||||
return Common::kNoGameDataFoundError;
|
||||
|
||||
// Save the savegame header
|
||||
CruiseSavegameHeader header;
|
||||
header.saveName = saveName;
|
||||
writeSavegameHeader(f, header);
|
||||
|
||||
if (f->err()) {
|
||||
delete f;
|
||||
saveMan->removeSavefile(filename);
|
||||
return Common::kWritingFailed;
|
||||
} else {
|
||||
// Create the remainder of the savegame
|
||||
Common::Serializer s(nullptr, f);
|
||||
DoSync(s);
|
||||
|
||||
f->finalize();
|
||||
delete f;
|
||||
return Common::kNoError;
|
||||
}
|
||||
}
|
||||
|
||||
Common::Error loadSavegameData(int saveGameIdx) {
|
||||
Common::String saveName;
|
||||
cellStruct *currentcellHead;
|
||||
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *f = saveMan->openForLoading(_vm->getSavegameFile(saveGameIdx));
|
||||
|
||||
if (f == nullptr) {
|
||||
printInfoBlackBox("Savegame not found...");
|
||||
waitForPlayerInput();
|
||||
return Common::kNoGameDataFoundError;
|
||||
}
|
||||
|
||||
printInfoBlackBox("Loading in progress...");
|
||||
|
||||
initVars();
|
||||
_vm->sound().stopMusic();
|
||||
|
||||
// Skip over the savegame header
|
||||
CruiseSavegameHeader header;
|
||||
if (!readSavegameHeader(f, header)) {
|
||||
delete f;
|
||||
return Common::kReadingFailed;
|
||||
}
|
||||
|
||||
// Synchronise the remaining data of the savegame
|
||||
Common::Serializer s(f, nullptr);
|
||||
DoSync(s);
|
||||
|
||||
delete f;
|
||||
|
||||
// Post processing
|
||||
|
||||
for (int j = 0; j < 64; j++)
|
||||
preloadData[j].ptr = nullptr;
|
||||
|
||||
for (int j = 1; j < numOfLoadedOverlay; j++) {
|
||||
if (overlayTable[j].alreadyLoaded) {
|
||||
overlayTable[j].alreadyLoaded = 0;
|
||||
loadOverlay(overlayTable[j].overlayName);
|
||||
|
||||
if (overlayTable[j].alreadyLoaded) {
|
||||
ovlDataStruct *ovlData = overlayTable[j].ovlData;
|
||||
|
||||
// overlay BSS
|
||||
|
||||
if (ovlRestoreData[j]._sBssSize) {
|
||||
if (ovlData->data4Ptr) {
|
||||
MemFree(ovlData->data4Ptr);
|
||||
}
|
||||
|
||||
ovlData->data4Ptr = ovlRestoreData[j]._pBss;
|
||||
ovlData->sizeOfData4 = ovlRestoreData[j]._sBssSize;
|
||||
}
|
||||
|
||||
// overlay object data
|
||||
|
||||
if (ovlRestoreData[j]._sNumObj) {
|
||||
if (ovlData->arrayObjVar) {
|
||||
MemFree(ovlData->arrayObjVar);
|
||||
}
|
||||
|
||||
ovlData->arrayObjVar = ovlRestoreData[j]._pObj;
|
||||
ovlData->size9 = ovlRestoreData[j]._sNumObj;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateAllScriptsImports();
|
||||
|
||||
lastAni[0] = 0;
|
||||
|
||||
for (int i = 0; i < NUM_FILE_ENTRIES; i++) {
|
||||
if (filesDatabase[i].subData.ptr) {
|
||||
int j = i + 1;
|
||||
for (; j < NUM_FILE_ENTRIES &&
|
||||
filesDatabase[j].subData.ptr &&
|
||||
!strcmp(filesDatabase[i].subData.name, filesDatabase[j].subData.name) &&
|
||||
(filesDatabase[j].subData.index == (j - i));
|
||||
j++)
|
||||
;
|
||||
|
||||
for (int k = i; k < j; k++) {
|
||||
filesDatabase[k].subData.ptr = nullptr;
|
||||
filesDatabase[k].subData.ptrMask = nullptr;
|
||||
}
|
||||
|
||||
/*if (j < 2) {
|
||||
error("Unsupported mono file load");
|
||||
//loadFileMode1(filesDatabase[j].subData.name,filesDatabase[j].subData.var4);
|
||||
} else */
|
||||
if (strlen(filesDatabase[i].subData.name) > 0) {
|
||||
loadFileRange(filesDatabase[i].subData.name, filesDatabase[i].subData.index, i, j - i);
|
||||
} else {
|
||||
filesDatabase[i].subData.ptr = nullptr;
|
||||
filesDatabase[i].subData.ptrMask = nullptr;
|
||||
}
|
||||
|
||||
i = j - 1;
|
||||
}
|
||||
}
|
||||
|
||||
lastAni[0] = 0;
|
||||
|
||||
currentcellHead = cellHead.next;
|
||||
|
||||
while (currentcellHead) {
|
||||
if (currentcellHead->type == 5) {
|
||||
assert(0);
|
||||
#if 0
|
||||
uint8 *ptr = mainProc14(currentcellHead->overlay, currentcellHead->idx);
|
||||
if (ptr)
|
||||
*(int16 *)(currentcellHead->datas+0x2E) = getSprite(ptr,*(int16 *)(currentcellHead->datas+0xE));
|
||||
else
|
||||
*(int16 *)(currentcellHead->datas+0x2E) = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
currentcellHead = currentcellHead->next;
|
||||
}
|
||||
|
||||
if (strlen(currentCtpName)) {
|
||||
loadCtFromSave = 1;
|
||||
initCt(currentCtpName);
|
||||
loadCtFromSave = 0;
|
||||
}
|
||||
//prepareFadeOut();
|
||||
//gfxModuleData.gfxFunction8();
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (strlen((char *)backgroundTable[j].name)) {
|
||||
loadBackground(backgroundTable[j].name, j);
|
||||
}
|
||||
}
|
||||
|
||||
regenerateBackgroundIncrust(&backgroundIncrustHead);
|
||||
|
||||
// to finish
|
||||
|
||||
changeCursor(CURSOR_NORMAL);
|
||||
mainDraw(true);
|
||||
flipScreen();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
45
engines/cruise/saveload.h
Normal file
45
engines/cruise/saveload.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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 CRUISE_SAVELOAD_H
|
||||
#define CRUISE_SAVELOAD_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
#define CRUISE_SAVEGAME_VERSION 1
|
||||
|
||||
struct CruiseSavegameHeader {
|
||||
uint8 version;
|
||||
Common::String saveName;
|
||||
Graphics::Surface *thumbnail;
|
||||
};
|
||||
|
||||
Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName);
|
||||
Common::Error loadSavegameData(int saveGameIdx);
|
||||
WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header, bool skipThumbnail = true);
|
||||
void initVars();
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
643
engines/cruise/script.cpp
Normal file
643
engines/cruise/script.cpp
Normal file
@@ -0,0 +1,643 @@
|
||||
/* 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 "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
scriptInstanceStruct relHead;
|
||||
scriptInstanceStruct procHead;
|
||||
|
||||
scriptInstanceStruct *currentScriptPtr;
|
||||
|
||||
int8 getByteFromScript() {
|
||||
int8 var = *(int8 *)(currentData3DataPtr + currentScriptPtr->scriptOffset);
|
||||
++currentScriptPtr->scriptOffset;
|
||||
|
||||
return (var);
|
||||
}
|
||||
|
||||
short int getShortFromScript() {
|
||||
short int var = (int16)READ_BE_UINT16(currentData3DataPtr + currentScriptPtr->scriptOffset);
|
||||
currentScriptPtr->scriptOffset += 2;
|
||||
|
||||
return (var);
|
||||
}
|
||||
|
||||
// load opcode
|
||||
int32 opcodeType0() {
|
||||
int index = 0;
|
||||
|
||||
switch (currentScriptOpcodeType) {
|
||||
case 0:
|
||||
pushVar(getShortFromScript());
|
||||
return (0);
|
||||
|
||||
case 5:
|
||||
index = saveOpcodeVar;
|
||||
// fall through
|
||||
case 1: {
|
||||
uint8 *address = nullptr;
|
||||
int type = getByteFromScript();
|
||||
int ovl = getByteFromScript();
|
||||
short int offset = getShortFromScript();
|
||||
offset += index;
|
||||
|
||||
int typ7 = type & 7;
|
||||
|
||||
if (!typ7) {
|
||||
return (-10); // unresloved link
|
||||
}
|
||||
|
||||
if (!ovl) {
|
||||
address = scriptDataPtrTable[typ7];
|
||||
} else { // TODO:
|
||||
if (!overlayTable[ovl].alreadyLoaded) {
|
||||
return (-7);
|
||||
}
|
||||
|
||||
if (!overlayTable[ovl].ovlData) {
|
||||
return (-4);
|
||||
}
|
||||
|
||||
if (typ7 == 5) {
|
||||
address = overlayTable[ovl].ovlData->data4Ptr;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
address += offset;
|
||||
|
||||
int size = (type >> 3) & 3;
|
||||
|
||||
if (size == 1) {
|
||||
address += index;
|
||||
pushVar((int16)READ_BE_UINT16(address));
|
||||
return 0;
|
||||
} else if (size == 2) {
|
||||
pushVar(*address);
|
||||
return 0;
|
||||
} else {
|
||||
error("Unsupported code in opcodeType0 case 1");
|
||||
}
|
||||
}
|
||||
case 2: {
|
||||
int16 var_16;
|
||||
int di = getByteFromScript();
|
||||
int si = getByteFromScript();
|
||||
int var_2 = getShortFromScript();
|
||||
|
||||
if (!si) {
|
||||
si = currentScriptPtr->overlayNumber;
|
||||
}
|
||||
|
||||
if (getSingleObjectParam(si, var_2, di, &var_16)) {
|
||||
return -10;
|
||||
}
|
||||
|
||||
pushVar(var_16);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
error("Unsupported type %d in opcodeType0", currentScriptOpcodeType);
|
||||
}
|
||||
}
|
||||
|
||||
// save opcode
|
||||
int32 opcodeType1() {
|
||||
int var = popVar();
|
||||
int offset = 0;
|
||||
|
||||
switch (currentScriptOpcodeType) {
|
||||
case 0:
|
||||
return (0); // strange, but happens also in original interpreter
|
||||
|
||||
case 5:
|
||||
offset = saveOpcodeVar;
|
||||
// fall through
|
||||
case 1: {
|
||||
int var_A = 0;
|
||||
|
||||
int byte1 = getByteFromScript();
|
||||
int byte2 = getByteFromScript();
|
||||
|
||||
int short1 = getShortFromScript();
|
||||
|
||||
int var_6 = byte1 & 7;
|
||||
|
||||
int var_C = short1;
|
||||
|
||||
uint8 *ptr = nullptr;
|
||||
int type2;
|
||||
|
||||
if (!var_6)
|
||||
return (-10);
|
||||
|
||||
var_C = short1;
|
||||
|
||||
if (byte2) {
|
||||
if (!overlayTable[byte2].alreadyLoaded) {
|
||||
return (-7);
|
||||
}
|
||||
|
||||
if (!overlayTable[byte2].ovlData) {
|
||||
return (-4);
|
||||
}
|
||||
|
||||
if (var_6 == 5) {
|
||||
ptr = overlayTable[byte2].ovlData->data4Ptr + var_C;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
} else {
|
||||
ptr = scriptDataPtrTable[var_6] + var_C;
|
||||
}
|
||||
|
||||
type2 = ((byte1 & 0x18) >> 3);
|
||||
|
||||
switch (type2) {
|
||||
case 1: {
|
||||
WRITE_BE_UINT16(ptr + var_A + offset * 2, var);
|
||||
return 0;
|
||||
}
|
||||
case 2: {
|
||||
assert (ptr);
|
||||
*(ptr + var_A + offset) = var;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
error("Unsupported code in opcodeType1 case 1");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int mode = getByteFromScript();
|
||||
int di = getByteFromScript();
|
||||
int var_4 = getShortFromScript();
|
||||
|
||||
if (!di) {
|
||||
di = currentScriptPtr->overlayNumber;
|
||||
}
|
||||
|
||||
if ((var == 0x85) && !strcmp((char *)currentCtpName, "S26.CTP") && !di && mode == 1) { // patch in bar
|
||||
var = 0x87;
|
||||
}
|
||||
|
||||
setObjectPosition(di, var_4, mode, var);
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
saveOpcodeVar = var;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unsupported type %d in opcodeType1", currentScriptOpcodeType);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32 opcodeType2() {
|
||||
int index = 0;
|
||||
switch (currentScriptOpcodeType) {
|
||||
case 5:
|
||||
index = saveOpcodeVar;
|
||||
// fall through
|
||||
case 1: {
|
||||
uint8* adresse = nullptr;
|
||||
int type = getByteFromScript();
|
||||
int overlay = getByteFromScript();
|
||||
|
||||
int offset = getShortFromScript();
|
||||
offset += index;
|
||||
|
||||
int typ7 = type & 7;
|
||||
if (!typ7) {
|
||||
return (-10);
|
||||
}
|
||||
if (!overlay) {
|
||||
adresse = scriptDataPtrTable[typ7];
|
||||
} else {
|
||||
if (!overlayTable[overlay].alreadyLoaded) {
|
||||
return (-7);
|
||||
}
|
||||
if (!overlayTable[overlay].ovlData) {
|
||||
return (-4);
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
adresse += offset;
|
||||
int size = (type >> 3) & 3;
|
||||
|
||||
if (size == 1) {
|
||||
adresse += index;
|
||||
pushPtr(adresse);
|
||||
} else if (size == 2) {
|
||||
pushPtr(adresse);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 opcodeType10() { // break
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32 opcodeType11() { // break
|
||||
return (1);
|
||||
}
|
||||
|
||||
int32 opcodeType4() { // test
|
||||
int boolVar = 0;
|
||||
|
||||
int var1 = popVar();
|
||||
int var2 = popVar();
|
||||
|
||||
switch (currentScriptOpcodeType) {
|
||||
case 0:
|
||||
if (var2 != var1)
|
||||
boolVar = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (var2 == var1)
|
||||
boolVar = 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (var2 < var1)
|
||||
boolVar = 1;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (var2 <= var1)
|
||||
boolVar = 1;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (var2 > var1)
|
||||
boolVar = 1;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (var2 >= var1)
|
||||
boolVar = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pushVar(boolVar);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32 opcodeType6() {
|
||||
int si = 0;
|
||||
|
||||
int pop = popVar();
|
||||
|
||||
if (!pop)
|
||||
si = 1;
|
||||
|
||||
if (pop < 0)
|
||||
si |= 4;
|
||||
|
||||
if (pop > 0)
|
||||
si |= 2;
|
||||
|
||||
currentScriptPtr->ccr = si;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32 opcodeType7() {
|
||||
int var1 = popVar();
|
||||
int var2 = popVar();
|
||||
|
||||
pushVar(var1);
|
||||
pushVar(var2);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32 opcodeType5() {
|
||||
int offset = currentScriptPtr->scriptOffset;
|
||||
int short1 = getShortFromScript();
|
||||
int newSi = short1 + offset;
|
||||
int bitMask = currentScriptPtr->ccr;
|
||||
|
||||
switch (currentScriptOpcodeType) {
|
||||
case 0:
|
||||
if (!(bitMask & 1))
|
||||
currentScriptPtr->scriptOffset = newSi;
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (bitMask & 1)
|
||||
currentScriptPtr->scriptOffset = newSi;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (bitMask & 2)
|
||||
currentScriptPtr->scriptOffset = newSi;
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (bitMask & 3)
|
||||
currentScriptPtr->scriptOffset = newSi;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (bitMask & 4)
|
||||
currentScriptPtr->scriptOffset = newSi;
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (bitMask & 5)
|
||||
currentScriptPtr->scriptOffset = newSi;
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
break; // never
|
||||
|
||||
case 7:
|
||||
currentScriptPtr->scriptOffset = newSi; //always
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32 opcodeType3() { // math
|
||||
int pop1 = popVar();
|
||||
int pop2 = popVar();
|
||||
|
||||
switch (currentScriptOpcodeType) {
|
||||
case 0:
|
||||
pushVar(pop1 + pop2);
|
||||
return (0);
|
||||
|
||||
case 1:
|
||||
if (pop2 == 0)
|
||||
error("opcodeType3 - Invalid value for pop2");
|
||||
pushVar(pop1 / pop2);
|
||||
return (0);
|
||||
|
||||
case 2:
|
||||
pushVar(pop1 - pop2);
|
||||
return (0);
|
||||
|
||||
case 3:
|
||||
pushVar(pop1 * pop2);
|
||||
return (0);
|
||||
|
||||
case 4:
|
||||
if (pop2 == 0)
|
||||
error("opcodeType3 - Invalid value for pop2");
|
||||
pushVar(pop1 % pop2);
|
||||
return (0);
|
||||
|
||||
case 7:
|
||||
case 5:
|
||||
pushVar(pop2 | pop1);
|
||||
return (0);
|
||||
|
||||
case 6:
|
||||
pushVar(pop2 & pop1);
|
||||
return (0);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 opcodeType9() { // stop script
|
||||
//debug("Stop a script of overlay %s", overlayTable[currentScriptPtr->overlayNumber].overlayName);
|
||||
currentScriptPtr->scriptNumber = -1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
void setupFuncArray() {
|
||||
for (int i = 0; i < 64; i++)
|
||||
opcodeTypeTable[i] = nullptr;
|
||||
|
||||
opcodeTypeTable[1] = opcodeType0;
|
||||
opcodeTypeTable[2] = opcodeType1;
|
||||
opcodeTypeTable[3] = opcodeType2;
|
||||
opcodeTypeTable[4] = opcodeType3;
|
||||
opcodeTypeTable[5] = opcodeType4;
|
||||
opcodeTypeTable[6] = opcodeType5;
|
||||
opcodeTypeTable[7] = opcodeType6;
|
||||
opcodeTypeTable[8] = opcodeType7;
|
||||
opcodeTypeTable[9] = opcodeType8;
|
||||
opcodeTypeTable[10] = opcodeType9;
|
||||
opcodeTypeTable[11] = opcodeType10;
|
||||
opcodeTypeTable[12] = opcodeType11;
|
||||
}
|
||||
|
||||
int removeScript(int overlay, int idx, scriptInstanceStruct *headPtr) {
|
||||
scriptInstanceStruct *scriptPtr = headPtr->nextScriptPtr;
|
||||
|
||||
while (scriptPtr) {
|
||||
if (scriptPtr->overlayNumber == overlay && (scriptPtr->scriptNumber == idx || idx == -1))
|
||||
scriptPtr->scriptNumber = -1;
|
||||
|
||||
scriptPtr = scriptPtr->nextScriptPtr;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint8 *attacheNewScriptToTail(scriptInstanceStruct *scriptHandlePtr, int16 overlayNumber, int16 param, int16 arg0, int16 arg1, int16 arg2, scriptTypeEnum scriptType) {
|
||||
int useArg3Neg = 0;
|
||||
ovlData3Struct *data3Ptr;
|
||||
int var_C;
|
||||
scriptInstanceStruct *oldTail;
|
||||
|
||||
if (scriptType < 0) {
|
||||
useArg3Neg = 1;
|
||||
scriptType = (scriptTypeEnum) -scriptType;
|
||||
}
|
||||
|
||||
if (scriptType == 20)
|
||||
data3Ptr = getOvlData3Entry(overlayNumber, param);
|
||||
else if (scriptType == 30)
|
||||
data3Ptr = scriptFunc1Sub2(overlayNumber, param);
|
||||
else
|
||||
return (nullptr);
|
||||
|
||||
if (!data3Ptr)
|
||||
return (nullptr);
|
||||
|
||||
if (!data3Ptr->dataPtr)
|
||||
return (nullptr);
|
||||
|
||||
var_C = data3Ptr->sysKey;
|
||||
oldTail = scriptHandlePtr;
|
||||
|
||||
while (oldTail->nextScriptPtr) // go to the end of the list
|
||||
oldTail = oldTail->nextScriptPtr;
|
||||
|
||||
scriptInstanceStruct *tempPtr = (scriptInstanceStruct *)mallocAndZero(sizeof(scriptInstanceStruct));
|
||||
|
||||
if (!tempPtr)
|
||||
return (nullptr);
|
||||
|
||||
tempPtr->data = nullptr;
|
||||
|
||||
if (var_C)
|
||||
tempPtr->data = (uint8 *) mallocAndZero(var_C);
|
||||
|
||||
tempPtr->dataSize = var_C;
|
||||
tempPtr->nextScriptPtr = nullptr;
|
||||
tempPtr->scriptOffset = 0;
|
||||
tempPtr->scriptNumber = param;
|
||||
tempPtr->overlayNumber = overlayNumber;
|
||||
|
||||
if (scriptType == 20) // Obj or not ?
|
||||
tempPtr->sysKey = useArg3Neg;
|
||||
else
|
||||
tempPtr->sysKey = 1;
|
||||
|
||||
tempPtr->freeze = 0;
|
||||
tempPtr->type = scriptType;
|
||||
tempPtr->var18 = arg2;
|
||||
tempPtr->var16 = arg1;
|
||||
tempPtr->var1A = arg0;
|
||||
tempPtr->nextScriptPtr = oldTail->nextScriptPtr; // should always be NULL as it's the tail
|
||||
oldTail->nextScriptPtr = tempPtr; // attach the new node to the list
|
||||
|
||||
return (tempPtr->data);
|
||||
}
|
||||
|
||||
int executeScripts(scriptInstanceStruct *ptr) {
|
||||
int numScript2;
|
||||
ovlData3Struct *ptr2;
|
||||
ovlDataStruct *ovlData;
|
||||
uint8 opcodeType;
|
||||
|
||||
numScript2 = ptr->scriptNumber;
|
||||
|
||||
if (ptr->type == 20)
|
||||
ptr2 = getOvlData3Entry(ptr->overlayNumber, numScript2);
|
||||
else if (ptr->type == 30)
|
||||
ptr2 = scriptFunc1Sub2(ptr->overlayNumber, numScript2);
|
||||
else
|
||||
return (-6);
|
||||
|
||||
if (!ptr2)
|
||||
return (-4);
|
||||
|
||||
if (!overlayTable[ptr->overlayNumber].alreadyLoaded)
|
||||
return (-7);
|
||||
|
||||
ovlData = overlayTable[ptr->overlayNumber].ovlData;
|
||||
|
||||
if (!ovlData)
|
||||
return (-4);
|
||||
|
||||
currentData3DataPtr = ptr2->dataPtr;
|
||||
scriptDataPtrTable[1] = (uint8 *) ptr->data;
|
||||
scriptDataPtrTable[2] = getDataFromData3(ptr2, 1);
|
||||
scriptDataPtrTable[5] = ovlData->data4Ptr; // free strings
|
||||
scriptDataPtrTable[6] = ovlData->ptr8;
|
||||
currentScriptPtr = ptr;
|
||||
positionInStack = 0;
|
||||
|
||||
do {
|
||||
#ifdef SKIP_INTRO
|
||||
if (currentScriptPtr->scriptOffset == 290
|
||||
&& currentScriptPtr->overlayNumber == 4
|
||||
&& currentScriptPtr->scriptNumber == 0) {
|
||||
currentScriptPtr->scriptOffset = 923;
|
||||
}
|
||||
#endif
|
||||
// FIXME: Delay for starting end credits is too long.
|
||||
// Fix it for now, but game rates really need looking into
|
||||
if (currentScriptPtr->overlayNumber == 71 &&
|
||||
currentScriptPtr->scriptOffset == 1884 &&
|
||||
positionInStack == 1) {
|
||||
popVar();
|
||||
pushVar(50);
|
||||
}
|
||||
|
||||
opcodeType = getByteFromScript();
|
||||
|
||||
debugC(5, kCruiseDebugScript, "Script %s/%d ip=%d opcode=%d",
|
||||
overlayTable[currentScriptPtr->overlayNumber].overlayName,
|
||||
currentScriptPtr->scriptNumber,
|
||||
currentScriptPtr->scriptOffset,
|
||||
(opcodeType & 0xFB) >> 3);
|
||||
|
||||
currentScriptOpcodeType = opcodeType & 7;
|
||||
|
||||
if (!opcodeTypeTable[(opcodeType & 0xFB) >> 3]) {
|
||||
error("Unsupported opcode type %d", (opcodeType & 0xFB) >> 3);
|
||||
}
|
||||
} while (!opcodeTypeTable[(opcodeType & 0xFB) >> 3]());
|
||||
|
||||
currentScriptPtr = nullptr;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void manageScripts(scriptInstanceStruct *scriptHandle) {
|
||||
scriptInstanceStruct *ptr = scriptHandle;
|
||||
|
||||
while (ptr) {
|
||||
if (!overlayTable[ptr->overlayNumber].executeScripts) {
|
||||
if ((ptr->scriptNumber != -1) && (ptr->freeze == 0) && (ptr->sysKey != 0))
|
||||
executeScripts(ptr);
|
||||
|
||||
if (ptr->sysKey == 0)
|
||||
ptr->sysKey = 1;
|
||||
}
|
||||
ptr = ptr->nextScriptPtr;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
63
engines/cruise/script.h
Normal file
63
engines/cruise/script.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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 CRUISE_SCRIPT_H
|
||||
#define CRUISE_SCRIPT_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
enum scriptTypeEnum {
|
||||
scriptType_MinusPROC = -20,
|
||||
scriptType_Minus30 = -30,
|
||||
scriptType_PROC = 20,
|
||||
scriptType_REL = 30
|
||||
};
|
||||
|
||||
struct scriptInstanceStruct {
|
||||
struct scriptInstanceStruct *nextScriptPtr;
|
||||
int16 ccr;
|
||||
int16 scriptOffset;
|
||||
uint8 *data;
|
||||
int16 dataSize;
|
||||
int16 scriptNumber;
|
||||
int16 overlayNumber;
|
||||
int16 sysKey;
|
||||
int16 freeze;
|
||||
scriptTypeEnum type;
|
||||
int16 var16;
|
||||
int16 var18;
|
||||
int16 var1A;
|
||||
};
|
||||
|
||||
extern scriptInstanceStruct relHead;
|
||||
extern scriptInstanceStruct procHead;
|
||||
extern scriptInstanceStruct *currentScriptPtr;
|
||||
|
||||
void setupFuncArray();
|
||||
int8 getByteFromScript();
|
||||
|
||||
int removeScript(int overlay, int idx, scriptInstanceStruct * headPtr);
|
||||
uint8 *attacheNewScriptToTail(scriptInstanceStruct *scriptHandlePtr, int16 overlayNumber, int16 param, int16 arg0, int16 arg1, int16 arg2, scriptTypeEnum scriptType);
|
||||
void manageScripts(scriptInstanceStruct * scriptHandle);
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
879
engines/cruise/sound.cpp
Normal file
879
engines/cruise/sound.cpp
Normal file
@@ -0,0 +1,879 @@
|
||||
/* 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/endian.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
#include "cruise/sound.h"
|
||||
#include "cruise/volume.h"
|
||||
|
||||
#include "audio/fmopl.h"
|
||||
|
||||
namespace Audio {
|
||||
class Mixer;
|
||||
}
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
class PCSoundDriver {
|
||||
public:
|
||||
typedef void (*UpdateCallback)(void *);
|
||||
|
||||
PCSoundDriver() :
|
||||
_upCb(nullptr),
|
||||
_upRef(nullptr),
|
||||
_musicVolume(0),
|
||||
_sfxVolume(0) {}
|
||||
virtual ~PCSoundDriver() {}
|
||||
|
||||
virtual void setupChannel(int channel, const byte *data, int instrument, int volume) = 0;
|
||||
virtual void setChannelFrequency(int channel, int frequency) = 0;
|
||||
virtual void stopChannel(int channel) = 0;
|
||||
virtual void playSample(const byte *data, int size, int channel, int volume) = 0;
|
||||
virtual void stopAll() = 0;
|
||||
virtual const char *getInstrumentExtension() const { return ""; }
|
||||
virtual void syncSounds();
|
||||
|
||||
void setUpdateCallback(UpdateCallback upCb, void *ref);
|
||||
void resetChannel(int channel);
|
||||
void findNote(int freq, int *note, int *oct) const;
|
||||
|
||||
|
||||
protected:
|
||||
UpdateCallback _upCb;
|
||||
void *_upRef;
|
||||
uint8 _musicVolume;
|
||||
uint8 _sfxVolume;
|
||||
|
||||
static const int _noteTable[];
|
||||
static const int _noteTableCount;
|
||||
};
|
||||
|
||||
const int PCSoundDriver::_noteTable[] = {
|
||||
0xEEE, 0xE17, 0xD4D, 0xC8C, 0xBD9, 0xB2F, 0xA8E, 0x9F7,
|
||||
0x967, 0x8E0, 0x861, 0x7E8, 0x777, 0x70B, 0x6A6, 0x647,
|
||||
0x5EC, 0x597, 0x547, 0x4FB, 0x4B3, 0x470, 0x430, 0x3F4,
|
||||
0x3BB, 0x385, 0x353, 0x323, 0x2F6, 0x2CB, 0x2A3, 0x27D,
|
||||
0x259, 0x238, 0x218, 0x1FA, 0x1DD, 0x1C2, 0x1A9, 0x191,
|
||||
0x17B, 0x165, 0x151, 0x13E, 0x12C, 0x11C, 0x10C, 0x0FD,
|
||||
0x0EE, 0x0E1, 0x0D4, 0x0C8, 0x0BD, 0x0B2, 0x0A8, 0x09F,
|
||||
0x096, 0x08E, 0x086, 0x07E, 0x077, 0x070, 0x06A, 0x064,
|
||||
0x05E, 0x059, 0x054, 0x04F, 0x04B, 0x047, 0x043, 0x03F,
|
||||
0x03B, 0x038, 0x035, 0x032, 0x02F, 0x02C, 0x02A, 0x027,
|
||||
0x025, 0x023, 0x021, 0x01F, 0x01D, 0x01C, 0x01A, 0x019,
|
||||
0x017, 0x016, 0x015, 0x013, 0x012, 0x011, 0x010, 0x00F
|
||||
};
|
||||
|
||||
const int PCSoundDriver::_noteTableCount = ARRAYSIZE(_noteTable);
|
||||
|
||||
struct AdLibRegisterSoundInstrument {
|
||||
uint8 vibrato;
|
||||
uint8 attackDecay;
|
||||
uint8 sustainRelease;
|
||||
uint8 feedbackStrength;
|
||||
uint8 keyScaling;
|
||||
uint8 outputLevel;
|
||||
uint8 freqMod;
|
||||
};
|
||||
|
||||
struct AdLibSoundInstrument {
|
||||
byte mode;
|
||||
byte channel;
|
||||
AdLibRegisterSoundInstrument regMod;
|
||||
AdLibRegisterSoundInstrument regCar;
|
||||
byte waveSelectMod;
|
||||
byte waveSelectCar;
|
||||
byte amDepth;
|
||||
};
|
||||
|
||||
struct VolumeEntry {
|
||||
int original;
|
||||
int adjusted;
|
||||
};
|
||||
|
||||
class AdLibSoundDriver : public PCSoundDriver {
|
||||
public:
|
||||
AdLibSoundDriver(Audio::Mixer *mixer);
|
||||
~AdLibSoundDriver() override;
|
||||
|
||||
// PCSoundDriver interface
|
||||
void setupChannel(int channel, const byte *data, int instrument, int volume) override;
|
||||
void stopChannel(int channel) override;
|
||||
void stopAll() override;
|
||||
|
||||
void initCard();
|
||||
void onTimer();
|
||||
void setupInstrument(const byte *data, int channel);
|
||||
void setupInstrument(const AdLibSoundInstrument *ins, int channel);
|
||||
void loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg);
|
||||
virtual void loadInstrument(const byte *data, AdLibSoundInstrument *asi) = 0;
|
||||
void syncSounds() override;
|
||||
|
||||
void adjustVolume(int channel, int volume);
|
||||
|
||||
protected:
|
||||
OPL::OPL *_opl;
|
||||
Audio::Mixer *_mixer;
|
||||
|
||||
byte _vibrato;
|
||||
VolumeEntry _channelsVolumeTable[5];
|
||||
AdLibSoundInstrument _instrumentsTable[5];
|
||||
|
||||
static const int _freqTable[];
|
||||
static const int _freqTableCount;
|
||||
static const int _operatorsTable[];
|
||||
static const int _operatorsTableCount;
|
||||
static const int _voiceOperatorsTable[];
|
||||
static const int _voiceOperatorsTableCount;
|
||||
};
|
||||
|
||||
const int AdLibSoundDriver::_freqTable[] = {
|
||||
0x157, 0x16C, 0x181, 0x198, 0x1B1, 0x1CB,
|
||||
0x1E6, 0x203, 0x222, 0x243, 0x266, 0x28A
|
||||
};
|
||||
|
||||
const int AdLibSoundDriver::_freqTableCount = ARRAYSIZE(_freqTable);
|
||||
|
||||
const int AdLibSoundDriver::_operatorsTable[] = {
|
||||
0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21
|
||||
};
|
||||
|
||||
const int AdLibSoundDriver::_operatorsTableCount = ARRAYSIZE(_operatorsTable);
|
||||
|
||||
const int AdLibSoundDriver::_voiceOperatorsTable[] = {
|
||||
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 16, 14, 14, 17, 17, 13, 13
|
||||
};
|
||||
|
||||
const int AdLibSoundDriver::_voiceOperatorsTableCount = ARRAYSIZE(_voiceOperatorsTable);
|
||||
|
||||
class AdLibSoundDriverADL : public AdLibSoundDriver {
|
||||
public:
|
||||
AdLibSoundDriverADL(Audio::Mixer *mixer) : AdLibSoundDriver(mixer) {}
|
||||
const char *getInstrumentExtension() const override { return ".ADL"; }
|
||||
void loadInstrument(const byte *data, AdLibSoundInstrument *asi) override;
|
||||
void setChannelFrequency(int channel, int frequency) override;
|
||||
void playSample(const byte *data, int size, int channel, int volume) override;
|
||||
};
|
||||
|
||||
class PCSoundFxPlayer {
|
||||
private:
|
||||
enum {
|
||||
NUM_INSTRUMENTS = 15,
|
||||
NUM_CHANNELS = 4
|
||||
};
|
||||
|
||||
void update();
|
||||
void handleEvents();
|
||||
void handlePattern(int channel, const byte *patternData);
|
||||
|
||||
char _musicName[33];
|
||||
bool _playing;
|
||||
bool _songPlayed;
|
||||
int _currentPos;
|
||||
int _currentOrder;
|
||||
int _numOrders;
|
||||
int _eventsDelay;
|
||||
bool _looping;
|
||||
int _fadeOutCounter;
|
||||
int _updateTicksCounter;
|
||||
int _instrumentsChannelTable[NUM_CHANNELS];
|
||||
byte *_sfxData;
|
||||
byte *_instrumentsData[NUM_INSTRUMENTS];
|
||||
PCSoundDriver *_driver;
|
||||
|
||||
public:
|
||||
PCSoundFxPlayer(PCSoundDriver *driver);
|
||||
~PCSoundFxPlayer();
|
||||
|
||||
bool load(const char *song);
|
||||
void play();
|
||||
void stop();
|
||||
void unload();
|
||||
void fadeOut();
|
||||
void doSync(Common::Serializer &s);
|
||||
|
||||
static void updateCallback(void *ref);
|
||||
|
||||
bool songLoaded() const { return _sfxData != nullptr; }
|
||||
bool songPlayed() const { return _songPlayed; }
|
||||
bool playing() const { return _playing; }
|
||||
uint8 numOrders() const { assert(_sfxData); return _sfxData[470]; }
|
||||
void setNumOrders(uint8 v) { assert(_sfxData); _sfxData[470] = v; }
|
||||
void setPattern(int offset, uint8 value) { assert(_sfxData); _sfxData[472 + offset] = value; }
|
||||
const char *musicName() { return _musicName; }
|
||||
|
||||
// Note: Original game never actually uses looping variable. Songs are hardcoded to loop
|
||||
bool looping() const { return _looping; }
|
||||
void setLooping(bool v) { _looping = v; }
|
||||
};
|
||||
|
||||
byte *readBundleSoundFile(const char *name) {
|
||||
// Load the correct file
|
||||
int fileIdx = findFileInDisks(name);
|
||||
if (fileIdx < 0) return nullptr;
|
||||
|
||||
int unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2;
|
||||
byte *data = (byte *)MemAlloc(unpackedSize);
|
||||
assert(data);
|
||||
|
||||
if (volumePtrToFileDescriptor[fileIdx].size + 2 != unpackedSize) {
|
||||
uint8 *packedBuffer = (uint8 *)mallocAndZero(volumePtrToFileDescriptor[fileIdx].size + 2);
|
||||
|
||||
loadPackedFileToMem(fileIdx, packedBuffer);
|
||||
|
||||
//uint32 realUnpackedSize = READ_BE_UINT32(packedBuffer + volumePtrToFileDescriptor[fileIdx].size - 4);
|
||||
|
||||
delphineUnpack(data, packedBuffer, volumePtrToFileDescriptor[fileIdx].size);
|
||||
|
||||
MemFree(packedBuffer);
|
||||
} else {
|
||||
loadPackedFileToMem(fileIdx, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void PCSoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) {
|
||||
_upCb = upCb;
|
||||
_upRef = ref;
|
||||
}
|
||||
|
||||
void PCSoundDriver::findNote(int freq, int *note, int *oct) const {
|
||||
*note = _noteTableCount - 1;
|
||||
for (int i = 0; i < _noteTableCount; ++i) {
|
||||
if (_noteTable[i] <= freq) {
|
||||
*note = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*oct = *note / 12;
|
||||
*note %= 12;
|
||||
}
|
||||
|
||||
void PCSoundDriver::resetChannel(int channel) {
|
||||
stopChannel(channel);
|
||||
stopAll();
|
||||
}
|
||||
|
||||
void PCSoundDriver::syncSounds() {
|
||||
bool mute = false;
|
||||
if (ConfMan.hasKey("mute"))
|
||||
mute = ConfMan.getBool("mute");
|
||||
|
||||
bool music_mute = mute;
|
||||
bool sfx_mute = mute;
|
||||
|
||||
if (!mute) {
|
||||
music_mute = ConfMan.getBool("music_mute");
|
||||
sfx_mute = ConfMan.getBool("sfx_mute");
|
||||
}
|
||||
|
||||
// Get the new music and sfx volumes
|
||||
_musicVolume = music_mute ? 0 : MIN(255, ConfMan.getInt("music_volume"));
|
||||
_sfxVolume = sfx_mute ? 0 : MIN(255, ConfMan.getInt("sfx_volume"));
|
||||
}
|
||||
|
||||
AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
|
||||
: _mixer(mixer) {
|
||||
_opl = OPL::Config::create();
|
||||
if (!_opl || !_opl->init())
|
||||
error("Failed to create OPL");
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
_channelsVolumeTable[i].original = 0;
|
||||
_channelsVolumeTable[i].adjusted = 0;
|
||||
}
|
||||
memset(_instrumentsTable, 0, sizeof(_instrumentsTable));
|
||||
initCard();
|
||||
|
||||
_musicVolume = ConfMan.getBool("music_mute") ? 0 : MIN(255, ConfMan.getInt("music_volume"));
|
||||
_sfxVolume = ConfMan.getBool("sfx_mute") ? 0 : MIN(255, ConfMan.getInt("sfx_volume"));
|
||||
|
||||
_opl->start(new Common::Functor0Mem<void, AdLibSoundDriver>(this, &AdLibSoundDriver::onTimer), 50);
|
||||
}
|
||||
|
||||
AdLibSoundDriver::~AdLibSoundDriver() {
|
||||
delete _opl;
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::syncSounds() {
|
||||
PCSoundDriver::syncSounds();
|
||||
|
||||
// Force all instruments to reload on the next playing point
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
adjustVolume(i, _channelsVolumeTable[i].original);
|
||||
AdLibSoundInstrument *ins = &_instrumentsTable[i];
|
||||
setupInstrument(ins, i);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::adjustVolume(int channel, int volume) {
|
||||
_channelsVolumeTable[channel].original = volume;
|
||||
|
||||
volume = CLIP(volume, 0, 80);
|
||||
volume += volume / 4;
|
||||
// The higher possible value for volume is 100
|
||||
|
||||
int volAdjust = (channel == 4) ? _sfxVolume : _musicVolume;
|
||||
volume = (volume * volAdjust) / 128;
|
||||
|
||||
if (volume > 127)
|
||||
volume = 127;
|
||||
|
||||
_channelsVolumeTable[channel].adjusted = volume;
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::setupChannel(int channel, const byte *data, int instrument, int volume) {
|
||||
assert(channel < 5);
|
||||
if (data) {
|
||||
adjustVolume(channel, volume);
|
||||
setupInstrument(data, channel);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::stopChannel(int channel) {
|
||||
assert(channel < 5);
|
||||
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
|
||||
if (ins->mode != 0 && ins->channel == 6) {
|
||||
channel = 6;
|
||||
}
|
||||
if (ins->mode == 0 || channel == 6) {
|
||||
_opl->writeReg(0xB0 | channel, 0);
|
||||
}
|
||||
if (ins->mode != 0) {
|
||||
_vibrato &= ~(1 << (10 - ins->channel));
|
||||
_opl->writeReg(0xBD, _vibrato);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::stopAll() {
|
||||
for (int i = 0; i < 18; ++i)
|
||||
_opl->writeReg(0x40 | _operatorsTable[i], 63);
|
||||
|
||||
for (int i = 0; i < 9; ++i)
|
||||
_opl->writeReg(0xB0 | i, 0);
|
||||
|
||||
_opl->writeReg(0xBD, 0);
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::initCard() {
|
||||
_vibrato = 0x20;
|
||||
_opl->writeReg(0xBD, _vibrato);
|
||||
_opl->writeReg(0x08, 0x40);
|
||||
|
||||
static const int oplRegs[] = { 0x40, 0x60, 0x80, 0x20, 0xE0 };
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
_opl->writeReg(0xB0 | i, 0);
|
||||
}
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
_opl->writeReg(0xC0 | i, 0);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++) {
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
_opl->writeReg(oplRegs[j] | _operatorsTable[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
_opl->writeReg(1, 0x20);
|
||||
_opl->writeReg(1, 0);
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::onTimer() {
|
||||
if (_upCb) {
|
||||
(*_upCb)(_upRef);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::setupInstrument(const byte *data, int channel) {
|
||||
assert(channel < 5);
|
||||
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
|
||||
loadInstrument(data, ins);
|
||||
|
||||
setupInstrument(ins, channel);
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::setupInstrument(const AdLibSoundInstrument *ins, int channel) {
|
||||
int mod, car, tmp;
|
||||
const AdLibRegisterSoundInstrument *reg;
|
||||
|
||||
if (ins->mode != 0) {
|
||||
mod = _operatorsTable[_voiceOperatorsTable[2 * ins->channel + 0]];
|
||||
car = _operatorsTable[_voiceOperatorsTable[2 * ins->channel + 1]];
|
||||
} else {
|
||||
mod = _operatorsTable[_voiceOperatorsTable[2 * channel + 0]];
|
||||
car = _operatorsTable[_voiceOperatorsTable[2 * channel + 1]];
|
||||
}
|
||||
|
||||
if (ins->mode == 0 || ins->channel == 6) {
|
||||
reg = &ins->regMod;
|
||||
_opl->writeReg(0x20 | mod, reg->vibrato);
|
||||
if (reg->freqMod) {
|
||||
tmp = reg->outputLevel & 0x3F;
|
||||
} else {
|
||||
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted;
|
||||
tmp = 63 - (2 * tmp + 127) / (2 * 127);
|
||||
}
|
||||
_opl->writeReg(0x40 | mod, tmp | (reg->keyScaling << 6));
|
||||
_opl->writeReg(0x60 | mod, reg->attackDecay);
|
||||
_opl->writeReg(0x80 | mod, reg->sustainRelease);
|
||||
if (ins->mode != 0) {
|
||||
_opl->writeReg(0xC0 | ins->channel, reg->feedbackStrength);
|
||||
} else {
|
||||
_opl->writeReg(0xC0 | channel, reg->feedbackStrength);
|
||||
}
|
||||
_opl->writeReg(0xE0 | mod, ins->waveSelectMod);
|
||||
}
|
||||
|
||||
reg = &ins->regCar;
|
||||
_opl->writeReg(0x20 | car, reg->vibrato);
|
||||
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted;
|
||||
tmp = 63 - (2 * tmp + 127) / (2 * 127);
|
||||
_opl->writeReg(0x40 | car, tmp | (reg->keyScaling << 6));
|
||||
_opl->writeReg(0x60 | car, reg->attackDecay);
|
||||
_opl->writeReg(0x80 | car, reg->sustainRelease);
|
||||
_opl->writeReg(0xE0 | car, ins->waveSelectCar);
|
||||
}
|
||||
|
||||
void AdLibSoundDriver::loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg) {
|
||||
reg->vibrato = 0;
|
||||
if (READ_LE_UINT16(data + 18)) { // amplitude vibrato
|
||||
reg->vibrato |= 0x80;
|
||||
}
|
||||
if (READ_LE_UINT16(data + 20)) { // frequency vibrato
|
||||
reg->vibrato |= 0x40;
|
||||
}
|
||||
if (READ_LE_UINT16(data + 10)) { // sustaining sound
|
||||
reg->vibrato |= 0x20;
|
||||
}
|
||||
if (READ_LE_UINT16(data + 22)) { // envelope scaling
|
||||
reg->vibrato |= 0x10;
|
||||
}
|
||||
reg->vibrato |= READ_LE_UINT16(data + 2) & 0xF; // frequency multiplier
|
||||
|
||||
reg->attackDecay = READ_LE_UINT16(data + 6) << 4; // attack rate
|
||||
reg->attackDecay |= READ_LE_UINT16(data + 12) & 0xF; // decay rate
|
||||
|
||||
reg->sustainRelease = READ_LE_UINT16(data + 8) << 4; // sustain level
|
||||
reg->sustainRelease |= READ_LE_UINT16(data + 14) & 0xF; // release rate
|
||||
|
||||
reg->feedbackStrength = READ_LE_UINT16(data + 4) << 1; // feedback
|
||||
if (READ_LE_UINT16(data + 24) == 0) { // frequency modulation
|
||||
reg->feedbackStrength |= 1;
|
||||
}
|
||||
|
||||
reg->keyScaling = READ_LE_UINT16(data);
|
||||
reg->outputLevel = READ_LE_UINT16(data + 16);
|
||||
reg->freqMod = READ_LE_UINT16(data + 24);
|
||||
}
|
||||
|
||||
void AdLibSoundDriverADL::loadInstrument(const byte *data, AdLibSoundInstrument *asi) {
|
||||
asi->mode = *data++;
|
||||
asi->channel = *data++;
|
||||
asi->waveSelectMod = *data++ & 3;
|
||||
asi->waveSelectCar = *data++ & 3;
|
||||
asi->amDepth = *data++;
|
||||
++data;
|
||||
loadRegisterInstrument(data, &asi->regMod); data += 26;
|
||||
loadRegisterInstrument(data, &asi->regCar); data += 26;
|
||||
}
|
||||
|
||||
void AdLibSoundDriverADL::setChannelFrequency(int channel, int frequency) {
|
||||
assert(channel < 5);
|
||||
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
|
||||
if (ins->mode != 0) {
|
||||
channel = ins->channel;
|
||||
if (channel == 9) {
|
||||
channel = 8;
|
||||
} else if (channel == 10) {
|
||||
channel = 7;
|
||||
}
|
||||
}
|
||||
int freq, note, oct;
|
||||
findNote(frequency, ¬e, &oct);
|
||||
|
||||
note += oct * 12;
|
||||
if (ins->amDepth) {
|
||||
note = ins->amDepth;
|
||||
}
|
||||
if (note < 0) {
|
||||
note = 0;
|
||||
}
|
||||
|
||||
freq = _freqTable[note % 12];
|
||||
_opl->writeReg(0xA0 | channel, freq);
|
||||
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
|
||||
if (ins->mode == 0) {
|
||||
freq |= 0x20;
|
||||
}
|
||||
_opl->writeReg(0xB0 | channel, freq);
|
||||
if (ins->mode != 0) {
|
||||
_vibrato |= 1 << (10 - channel);
|
||||
_opl->writeReg(0xBD, _vibrato);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, int volume) {
|
||||
assert(channel < 5);
|
||||
adjustVolume(channel, 127);
|
||||
|
||||
setupInstrument(data, channel);
|
||||
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
|
||||
if (ins->mode != 0 && ins->channel == 6) {
|
||||
_opl->writeReg(0xB0 | channel, 0);
|
||||
}
|
||||
if (ins->mode != 0) {
|
||||
_vibrato &= ~(1 << (10 - ins->channel));
|
||||
_opl->writeReg(0xBD, _vibrato);
|
||||
}
|
||||
if (ins->mode != 0) {
|
||||
channel = ins->channel;
|
||||
if (channel == 9) {
|
||||
channel = 8;
|
||||
} else if (channel == 10) {
|
||||
channel = 7;
|
||||
}
|
||||
}
|
||||
uint16 note = 48;
|
||||
if (ins->amDepth) {
|
||||
note = ins->amDepth;
|
||||
}
|
||||
int freq = _freqTable[note % 12];
|
||||
_opl->writeReg(0xA0 | channel, freq);
|
||||
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
|
||||
if (ins->mode == 0) {
|
||||
freq |= 0x20;
|
||||
}
|
||||
_opl->writeReg(0xB0 | channel, freq);
|
||||
if (ins->mode != 0) {
|
||||
_vibrato |= 1 << (10 - channel);
|
||||
_opl->writeReg(0xBD, _vibrato);
|
||||
}
|
||||
}
|
||||
|
||||
PCSoundFxPlayer::PCSoundFxPlayer(PCSoundDriver *driver)
|
||||
: _playing(false), _songPlayed(false), _driver(driver) {
|
||||
memset(_instrumentsData, 0, sizeof(_instrumentsData));
|
||||
_sfxData = nullptr;
|
||||
_fadeOutCounter = 0;
|
||||
_driver->setUpdateCallback(updateCallback, this);
|
||||
|
||||
_currentPos = 0;
|
||||
_currentOrder = 0;
|
||||
_numOrders = 0;
|
||||
_eventsDelay = 0;
|
||||
_looping = false;
|
||||
_updateTicksCounter = 0;
|
||||
}
|
||||
|
||||
PCSoundFxPlayer::~PCSoundFxPlayer() {
|
||||
_driver->setUpdateCallback(nullptr, nullptr);
|
||||
stop();
|
||||
}
|
||||
|
||||
bool PCSoundFxPlayer::load(const char *song) {
|
||||
debug(9, "PCSoundFxPlayer::load('%s')", song);
|
||||
|
||||
/* stop (w/ fade out) the previous song */
|
||||
while (_fadeOutCounter != 0 && _fadeOutCounter < 100) {
|
||||
g_system->delayMillis(50);
|
||||
}
|
||||
_fadeOutCounter = 0;
|
||||
|
||||
if (_playing) {
|
||||
stop();
|
||||
}
|
||||
|
||||
Common::strlcpy(_musicName, song, sizeof(_musicName));
|
||||
_songPlayed = false;
|
||||
_looping = false;
|
||||
_sfxData = readBundleSoundFile(song);
|
||||
if (!_sfxData) {
|
||||
warning("Unable to load soundfx module '%s'", song);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
|
||||
_instrumentsData[i] = nullptr;
|
||||
|
||||
char instrument[64];
|
||||
memset(instrument, 0, 64); // Clear the data first
|
||||
memcpy(instrument, _sfxData + 20 + i * 30, 12);
|
||||
instrument[63] = '\0';
|
||||
|
||||
if (strlen(instrument) != 0) {
|
||||
char *dot = strrchr(instrument, '.');
|
||||
if (dot) {
|
||||
*dot = '\0';
|
||||
}
|
||||
Common::strlcat(instrument, _driver->getInstrumentExtension(), sizeof(instrument));
|
||||
_instrumentsData[i] = readBundleSoundFile(instrument);
|
||||
if (!_instrumentsData[i]) {
|
||||
warning("Unable to load soundfx instrument '%s'", instrument);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::play() {
|
||||
debug(9, "PCSoundFxPlayer::play()");
|
||||
if (_sfxData) {
|
||||
for (int i = 0; i < NUM_CHANNELS; ++i) {
|
||||
_instrumentsChannelTable[i] = -1;
|
||||
}
|
||||
_currentPos = 0;
|
||||
_currentOrder = 0;
|
||||
_numOrders = _sfxData[470];
|
||||
_eventsDelay = (244 - _sfxData[471]) * 100 / 1060;
|
||||
_updateTicksCounter = 0;
|
||||
_playing = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::stop() {
|
||||
if (_playing || _fadeOutCounter != 0) {
|
||||
_fadeOutCounter = 0;
|
||||
_playing = false;
|
||||
for (int i = 0; i < NUM_CHANNELS; ++i) {
|
||||
_driver->stopChannel(i);
|
||||
}
|
||||
_driver->stopAll();
|
||||
}
|
||||
unload();
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::fadeOut() {
|
||||
if (_playing) {
|
||||
_fadeOutCounter = 1;
|
||||
_playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::updateCallback(void *ref) {
|
||||
((PCSoundFxPlayer *)ref)->update();
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::update() {
|
||||
if (_playing || (_fadeOutCounter != 0 && _fadeOutCounter < 100)) {
|
||||
++_updateTicksCounter;
|
||||
if (_updateTicksCounter > _eventsDelay) {
|
||||
handleEvents();
|
||||
_updateTicksCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::handleEvents() {
|
||||
const byte *patternData = _sfxData + 600 + 1800;
|
||||
const byte *orderTable = _sfxData + 472;
|
||||
uint16 patternNum = orderTable[_currentOrder] * 1024;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
handlePattern(i, patternData + patternNum + _currentPos);
|
||||
patternData += 4;
|
||||
}
|
||||
|
||||
if (_fadeOutCounter != 0 && _fadeOutCounter < 100) {
|
||||
_fadeOutCounter += 2;
|
||||
}
|
||||
if (_fadeOutCounter >= 100) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
_currentPos += 16;
|
||||
if (_currentPos >= 1024) {
|
||||
_currentPos = 0;
|
||||
++_currentOrder;
|
||||
if (_currentOrder == _numOrders) {
|
||||
_currentOrder = 0;
|
||||
}
|
||||
}
|
||||
debug(7, "_currentOrder=%d/%d _currentPos=%d", _currentOrder, _numOrders, _currentPos);
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::handlePattern(int channel, const byte *patternData) {
|
||||
int instrument = patternData[2] >> 4;
|
||||
if (instrument != 0) {
|
||||
--instrument;
|
||||
if (_instrumentsChannelTable[channel] != instrument || _fadeOutCounter != 0) {
|
||||
_instrumentsChannelTable[channel] = instrument;
|
||||
const int volume = _sfxData[instrument] - _fadeOutCounter;
|
||||
_driver->setupChannel(channel, _instrumentsData[instrument], instrument, volume);
|
||||
}
|
||||
}
|
||||
int16 freq = (int16)READ_BE_UINT16(patternData);
|
||||
if (freq > 0) {
|
||||
_driver->stopChannel(channel);
|
||||
_driver->setChannelFrequency(channel, freq);
|
||||
}
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::unload() {
|
||||
for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
|
||||
MemFree(_instrumentsData[i]);
|
||||
_instrumentsData[i] = nullptr;
|
||||
}
|
||||
MemFree(_sfxData);
|
||||
_sfxData = nullptr;
|
||||
_songPlayed = true;
|
||||
}
|
||||
|
||||
void PCSoundFxPlayer::doSync(Common::Serializer &s) {
|
||||
s.syncBytes((byte *)_musicName, 33);
|
||||
uint16 v = (uint16)songLoaded();
|
||||
s.syncAsSint16LE(v);
|
||||
|
||||
if (s.isLoading() && v) {
|
||||
load(_musicName);
|
||||
|
||||
for (int i = 0; i < NUM_CHANNELS; ++i) {
|
||||
_instrumentsChannelTable[i] = -1;
|
||||
}
|
||||
|
||||
_numOrders = _sfxData[470];
|
||||
_eventsDelay = (244 - _sfxData[471]) * 100 / 1060;
|
||||
_updateTicksCounter = 0;
|
||||
}
|
||||
|
||||
s.syncAsSint16LE(_songPlayed);
|
||||
s.syncAsSint16LE(_looping);
|
||||
s.syncAsSint16LE(_currentPos);
|
||||
s.syncAsSint16LE(_currentOrder);
|
||||
s.syncAsSint16LE(_playing);
|
||||
}
|
||||
|
||||
PCSound::PCSound(Audio::Mixer *mixer, CruiseEngine *vm) {
|
||||
_vm = vm;
|
||||
_mixer = mixer;
|
||||
_soundDriver = new AdLibSoundDriverADL(_mixer);
|
||||
_player = new PCSoundFxPlayer(_soundDriver);
|
||||
_genVolume = 0;
|
||||
}
|
||||
|
||||
PCSound::~PCSound() {
|
||||
delete _player;
|
||||
delete _soundDriver;
|
||||
}
|
||||
|
||||
void PCSound::loadMusic(const char *name) {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::loadMusic('%s')", name);
|
||||
_player->load(name);
|
||||
}
|
||||
|
||||
void PCSound::playMusic() {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::playMusic()");
|
||||
_player->play();
|
||||
}
|
||||
|
||||
void PCSound::stopMusic() {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::stopMusic()");
|
||||
_player->stop();
|
||||
}
|
||||
|
||||
void PCSound::removeMusic() {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::removeMusic()");
|
||||
_player->unload();
|
||||
}
|
||||
|
||||
void PCSound::fadeOutMusic() {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::fadeOutMusic()");
|
||||
_player->fadeOut();
|
||||
}
|
||||
|
||||
void PCSound::playSound(const uint8 *data, int size, int volume) {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::playSound() channel %d size %d", 4, size);
|
||||
_soundDriver->playSample(data, size, 4, volume);
|
||||
}
|
||||
|
||||
void PCSound::stopSound(int channel) {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::stopSound() channel %d", channel);
|
||||
_soundDriver->resetChannel(channel);
|
||||
}
|
||||
|
||||
void PCSound::stopChannel(int channel) {
|
||||
debugC(5, kCruiseDebugSound, "PCSound::stopChannel() channel %d", channel);
|
||||
_soundDriver->stopChannel(channel);
|
||||
}
|
||||
|
||||
bool PCSound::isPlaying() const {
|
||||
return _player->playing();
|
||||
}
|
||||
|
||||
bool PCSound::songLoaded() const {
|
||||
return _player->songLoaded();
|
||||
}
|
||||
|
||||
bool PCSound::songPlayed() const {
|
||||
return _player->songPlayed();
|
||||
}
|
||||
|
||||
void PCSound::fadeSong() {
|
||||
_player->fadeOut();
|
||||
}
|
||||
|
||||
uint8 PCSound::numOrders() const {
|
||||
return _player->numOrders();
|
||||
}
|
||||
|
||||
void PCSound::setNumOrders(uint8 v) {
|
||||
_player->setNumOrders(v);
|
||||
}
|
||||
|
||||
void PCSound::setPattern(int offset, uint8 value) {
|
||||
_player->setPattern(offset, value);
|
||||
}
|
||||
|
||||
bool PCSound::musicLooping() const {
|
||||
return _player->looping();
|
||||
}
|
||||
|
||||
void PCSound::musicLoop(bool v) {
|
||||
_player->setLooping(v);
|
||||
}
|
||||
|
||||
void PCSound::startNote(int channel, int volume, int freq) {
|
||||
warning("TODO: startNote");
|
||||
// _soundDriver->setVolume(channel, volume);
|
||||
_soundDriver->setChannelFrequency(channel, freq);
|
||||
}
|
||||
|
||||
void PCSound::doSync(Common::Serializer &s) {
|
||||
_player->doSync(s);
|
||||
s.syncAsSint16LE(_genVolume);
|
||||
}
|
||||
|
||||
const char *PCSound::musicName() {
|
||||
return _player->musicName();
|
||||
}
|
||||
|
||||
void PCSound::syncSounds() {
|
||||
_soundDriver->syncSounds();
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
77
engines/cruise/sound.h
Normal file
77
engines/cruise/sound.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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 CRUISE_SOUND_H
|
||||
#define CRUISE_SOUND_H
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/serializer.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
class CruiseEngine;
|
||||
class PCSoundDriver;
|
||||
class PCSoundFxPlayer;
|
||||
|
||||
class PCSound {
|
||||
private:
|
||||
Audio::Mixer *_mixer;
|
||||
CruiseEngine *_vm;
|
||||
int _genVolume;
|
||||
protected:
|
||||
PCSoundDriver *_soundDriver;
|
||||
PCSoundFxPlayer *_player;
|
||||
public:
|
||||
PCSound(Audio::Mixer *mixer, CruiseEngine *vm);
|
||||
virtual ~PCSound();
|
||||
|
||||
virtual void loadMusic(const char *name);
|
||||
virtual void playMusic();
|
||||
virtual void stopMusic();
|
||||
virtual void removeMusic();
|
||||
virtual void fadeOutMusic();
|
||||
|
||||
virtual void playSound(const uint8 *data, int size, int volume);
|
||||
virtual void stopSound(int channel);
|
||||
|
||||
void doSync(Common::Serializer &s);
|
||||
const char *musicName();
|
||||
void stopChannel(int channel);
|
||||
bool isPlaying() const;
|
||||
bool songLoaded() const;
|
||||
bool songPlayed() const;
|
||||
void fadeSong();
|
||||
uint8 numOrders() const;
|
||||
void setNumOrders(uint8 v);
|
||||
void setPattern(int offset, uint8 value);
|
||||
bool musicLooping() const;
|
||||
void musicLoop(bool v);
|
||||
void startNote(int channel, int volume, int freq);
|
||||
void syncSounds();
|
||||
|
||||
// Note: Volume variable accessed by these methods is never actually used in original game
|
||||
void setVolume(int volume) { _genVolume = volume; }
|
||||
uint8 getVolume() const { return _genVolume; }
|
||||
};
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
73
engines/cruise/stack.cpp
Normal file
73
engines/cruise/stack.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
// 4 type bigger than the old one, but much safer/cleaner
|
||||
stackElementStruct scriptStack[SIZE_STACK];
|
||||
|
||||
// VAR
|
||||
|
||||
void pushVar(int16 var) {
|
||||
if (positionInStack < SIZE_STACK) {
|
||||
scriptStack[positionInStack].data.shortVar = var;
|
||||
scriptStack[positionInStack].type = STACK_SHORT;
|
||||
positionInStack++;
|
||||
}
|
||||
}
|
||||
|
||||
int16 popVar() {
|
||||
if (positionInStack <= 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
positionInStack--;
|
||||
|
||||
assert(scriptStack[positionInStack].type == STACK_SHORT);
|
||||
|
||||
return (scriptStack[positionInStack].data.shortVar);
|
||||
}
|
||||
|
||||
//// PTR
|
||||
|
||||
void pushPtr(void *ptr) {
|
||||
if (positionInStack < SIZE_STACK) {
|
||||
scriptStack[positionInStack].data.ptrVar = ptr;
|
||||
scriptStack[positionInStack].type = STACK_PTR;
|
||||
positionInStack++;
|
||||
}
|
||||
}
|
||||
|
||||
void *popPtr() {
|
||||
if (positionInStack <= 0) {
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
positionInStack--;
|
||||
|
||||
assert(scriptStack[positionInStack].type == STACK_PTR);
|
||||
|
||||
return (scriptStack[positionInStack].data.ptrVar);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
53
engines/cruise/stack.h
Normal file
53
engines/cruise/stack.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 CRUISE_STACK_H
|
||||
#define CRUISE_STACK_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
// TODO: Replace this with Common::Stack
|
||||
|
||||
#define SIZE_STACK 0x200
|
||||
|
||||
enum stackElementTypeEnum {
|
||||
STACK_SHORT,
|
||||
STACK_PTR
|
||||
};
|
||||
|
||||
struct stackElementStruct {
|
||||
stackElementTypeEnum type;
|
||||
|
||||
union {
|
||||
void *ptrVar;
|
||||
int16 shortVar;
|
||||
} data;
|
||||
};
|
||||
|
||||
int16 popVar();
|
||||
void pushVar(int16 var);
|
||||
|
||||
void pushPtr(void *ptr);
|
||||
void *popPtr();
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
365
engines/cruise/staticres.cpp
Normal file
365
engines/cruise/staticres.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/* 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 "cruise/staticres.h"
|
||||
#include "cruise/cruise.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
const int actor_move[][13] = {
|
||||
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0}, // back
|
||||
{13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0}, // right side
|
||||
{25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 0}, // front
|
||||
{ -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, 0}// left side
|
||||
};
|
||||
|
||||
const int actor_end[][13] = {
|
||||
{37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // stat back
|
||||
{38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // stat right-side
|
||||
{39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // stat front
|
||||
{ -38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // stat left-side
|
||||
};
|
||||
|
||||
const int actor_stat[][13] = {
|
||||
{53, 54, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{59, 60, 62, 63, 78, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ -78, -63, -62, -60, -59, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ -57, -56, -55, -54, -53, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
const int actor_invstat[][13] = {
|
||||
{ -53, -54, -55, -56, -57, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{57, 56, 55, 54, 53, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{78, 63, 62, 60, 59, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ -59, -60, -62, -63, -78, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
// font character lookup tables
|
||||
|
||||
const int16 english_fontCharacterTable[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
|
||||
86, 87, 88, 89, 90, 91, 92,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
106, 105,
|
||||
-1, -1, -1, -1,
|
||||
107, 108,
|
||||
-1, -1,
|
||||
109, 110,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
111, -1,
|
||||
112,
|
||||
-1, -1,
|
||||
113,
|
||||
114,
|
||||
-1,
|
||||
-1,
|
||||
116, 93,
|
||||
-1,
|
||||
118,
|
||||
-1,
|
||||
94,
|
||||
-1,
|
||||
117,
|
||||
115,
|
||||
96,
|
||||
95,
|
||||
97,
|
||||
98,
|
||||
-1,
|
||||
-1,
|
||||
99,
|
||||
100,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
101,
|
||||
-1,
|
||||
102,
|
||||
-1,
|
||||
-1,
|
||||
103,
|
||||
-1,
|
||||
104,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
};
|
||||
|
||||
const int16 german_fontCharacterTable[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
|
||||
86, 87, 88, 89, 90, 91, 92,
|
||||
-1, -1, -1,
|
||||
0x72,
|
||||
-1, -1,
|
||||
0x5e,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x6a,
|
||||
-1, -1, -1, -1, -1,
|
||||
0x66,
|
||||
-1, -1, -1, -1,
|
||||
0x70, 0x78,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1,
|
||||
0x6a, 0x69,
|
||||
-1, -1, -1, -1,
|
||||
0x6b, 0x6c,
|
||||
-1, -1,
|
||||
0x6d, 0x6e,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
0x6f,
|
||||
-1,
|
||||
0x70,
|
||||
-1, -1,
|
||||
0x71, 0x72,
|
||||
-1, -1,
|
||||
0x74, 0x5D, 0x74, 0x76,
|
||||
-1,
|
||||
0x5E,
|
||||
-1,
|
||||
0x75, 0x73, 0x60, 0x5F, 0x61, 0x62,
|
||||
-1, -1,
|
||||
0x63, 0x64,
|
||||
-1, -1, -1, -1
|
||||
};
|
||||
|
||||
const int16 spanish_fontCharacterTable[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
|
||||
86, 87, 88, 89, 90, 91, 92,
|
||||
-1, -1, -1,
|
||||
0x72, 0x80,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x7f, 0x79, 0x7b, 0x81, 0x82, 0x83,
|
||||
-1, -1,
|
||||
0x7d,
|
||||
-1, -1, -1, -1,
|
||||
0x7E,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
0x6A, 0x69,
|
||||
-1, -1, -1, -1,
|
||||
0x6B, 0x6C,
|
||||
-1, -1,
|
||||
0x6D, 0x6E,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
0x6F,
|
||||
-1,
|
||||
0x70,
|
||||
-1, -1,
|
||||
0x71, 0x72,
|
||||
-1, -1,
|
||||
0x74, 0x5D,
|
||||
-1,
|
||||
0x76,
|
||||
-1,
|
||||
0x5E,
|
||||
-1,
|
||||
0x75, 0x73, 0x60, 0x5F, 0x61, 0x62, 0x79, 0x78, 0x63, 0x64,
|
||||
-1, -1,
|
||||
0x7B, 0x7A,
|
||||
0x65,
|
||||
-1,
|
||||
0x66,
|
||||
-1, -1,
|
||||
0x67,
|
||||
-1,
|
||||
0x68,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int16 russian_fontCharacterTable[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
|
||||
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222
|
||||
};
|
||||
|
||||
//
|
||||
// Mouse data
|
||||
//
|
||||
|
||||
const byte mouseCursorNormal[] = {
|
||||
0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00,
|
||||
0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00,
|
||||
0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00,
|
||||
0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
|
||||
0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x00,
|
||||
0xFC, 0x00, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x80,
|
||||
0xFF, 0xC0, 0xFF, 0xC0, 0xFE, 0x00, 0xFF, 0x00,
|
||||
0xCF, 0x00, 0x07, 0x80, 0x07, 0x80, 0x03, 0x80
|
||||
};
|
||||
|
||||
const byte mouseCursorDisk[] = {
|
||||
0x7F, 0xFC, 0x9F, 0x12, 0x9F, 0x12, 0x9F, 0x12,
|
||||
0x9F, 0x12, 0x9F, 0xE2, 0x80, 0x02, 0x9F, 0xF2,
|
||||
0xA0, 0x0A, 0xA0, 0x0A, 0xA0, 0x0A, 0xA0, 0x0A,
|
||||
0xA0, 0x0A, 0xA0, 0x0A, 0x7F, 0xFC, 0x00, 0x00,
|
||||
|
||||
0x7F, 0xFC, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
|
||||
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
|
||||
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
|
||||
0xFF, 0xFE, 0xFF, 0xFE, 0x7F, 0xFC, 0x00, 0x00
|
||||
};
|
||||
|
||||
const byte mouseCursorCross[] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7C, 0x7C,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
|
||||
0x03, 0x80, 0x03, 0x80, 0xFF, 0xFE, 0xFE, 0xFE,
|
||||
0xFF, 0xFE, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
|
||||
0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00
|
||||
};
|
||||
|
||||
const byte mouseCursorNoMouse[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const byte mouseCursorWalk[] = {
|
||||
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0xE0,
|
||||
0x03, 0xF0, 0x03, 0x38, 0x1B, 0xDC, 0x1B, 0xCC,
|
||||
0x03, 0xCC, 0x03, 0x80, 0x07, 0x00, 0x0E, 0xC0,
|
||||
0x1C, 0xE0, 0x18, 0x70, 0x18, 0x38, 0x18, 0x18,
|
||||
|
||||
0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x03, 0xF0,
|
||||
0x07, 0xF8, 0x07, 0xFC, 0x3F, 0xFE, 0x3F, 0xFE,
|
||||
0x07, 0xFE, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xE0,
|
||||
0x3F, 0xF0, 0x3C, 0xF8, 0x3C, 0x7C, 0x3C, 0x3C
|
||||
};
|
||||
|
||||
const byte mouseCursorExit[] = {
|
||||
0x7f, 0xf8, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18,
|
||||
0x60, 0x00, 0x60, 0x08, 0x60, 0x0c, 0x60, 0xfe,
|
||||
0x60, 0xfe, 0x60, 0x0c, 0x60, 0x08, 0x60, 0x00,
|
||||
0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x7f, 0xf8,
|
||||
|
||||
0xff, 0xfc, 0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c,
|
||||
0xf0, 0x00, 0xf0, 0x1c, 0xf0, 0x1e, 0xf1, 0xff,
|
||||
0xf1, 0xff, 0xf0, 0x1e, 0xf0, 0x1c, 0xf0, 0x00,
|
||||
0xf0, 0x3c, 0xf0, 0x3c, 0xf0, 0x3c, 0xff, 0xfc
|
||||
};
|
||||
|
||||
const byte mouseCursorMagnifyingGlass[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x00, 0x22, 0x00, 0x02,
|
||||
0x07, 0x82, 0x03, 0x82, 0x07, 0x9e, 0xfe, 0x80,
|
||||
0xfc, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x07, 0xff, 0x07, 0xff, 0x06, 0x03,
|
||||
0x06, 0x03, 0x06, 0x03, 0x00, 0x23, 0x0f, 0xc3,
|
||||
0x0f, 0xc3, 0x07, 0xc3, 0xff, 0xdf, 0xff, 0xdf,
|
||||
0xfe, 0xc0, 0xfc, 0x00, 0xf8, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const char *englishLanguageStrings[13] = {
|
||||
"Pause", nullptr, nullptr, nullptr, nullptr, "Inventory", "Speak about...", "Player Menu", nullptr,
|
||||
"Save", "Load", "Start Again", "Quit"
|
||||
};
|
||||
const char *frenchLanguageStrings[13] = {
|
||||
"", nullptr, nullptr, nullptr, nullptr, "Inventaire", "Parler de...", "Menu Joueur", nullptr,
|
||||
"Sauvegarde", "Chargement", "Recommencer le jeu", "Quitter"
|
||||
};
|
||||
// The original Amiga version does use "Speilermen\xFC" instead of "Spielermen\xFC", if we want to correct
|
||||
// this typo, we can easily do so.
|
||||
const char *germanLanguageStrings[13] = {
|
||||
" ", nullptr, nullptr, nullptr, nullptr, "Inventar", "Sprechen ""\xFC""ber", "Speilermen\xFC", "Speicherlaufwerk",
|
||||
"Speichern", "Laden", "Neu beginnen", "Ende"
|
||||
};
|
||||
const char *italianLanguageStrings[13] = {
|
||||
"Pausa", nullptr, nullptr, nullptr, nullptr, "Inventario", "Parla di...", "Menu giocatore", nullptr,
|
||||
"Salva", "Carica", "Ricomincia", "Esci"
|
||||
};
|
||||
|
||||
const char *spanishLanguageStrings[13] = {
|
||||
"Pausa", nullptr, nullptr, nullptr, nullptr, "Inventario", "Hablar de...", "Menu del jugador", nullptr,
|
||||
"Salvar", "Cargar", "Recomenzar", "Salir"
|
||||
};
|
||||
|
||||
const char *russianLanguageStrings[13] = {
|
||||
"\x8F\xA0\xE3\xA7\xA0", // Пауза
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
"\x82\xA5\xE9\xA8", // "Вещи",
|
||||
"\x8F\xAE\xA3\xAE\xA2\xAE\xE0\xA8\xE2\xEC\x20\xAE\x2E\x2E\x2E", // "Поговорить о...",
|
||||
"\x8C\xA5\xAD\xEE\x20\xA8\xA3\xE0\xEB", // "Меню игры",
|
||||
nullptr, // nullptr,
|
||||
"\x91\xAE\xE5\xE0\xA0\xAD\xA8\xE2\xEC", // "Сохранить",
|
||||
"\x87\xA0\xA3\xE0\xE3\xA7\xA8\xE2\xEC", // "Загрузить",
|
||||
"\x87\xA0\xAD\xAE\xA2\xAE", // "Заново",
|
||||
"\x82\xEB\xA9\xE2\xA8" // "Выйти"
|
||||
};
|
||||
|
||||
} // End of namespace Cruise
|
||||
68
engines/cruise/staticres.h
Normal file
68
engines/cruise/staticres.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 CRUISE_STATICRES_H
|
||||
#define CRUISE_STATICRES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "cruise/cruise.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
extern const int actor_move[][13];
|
||||
|
||||
extern const int actor_end[][13];
|
||||
|
||||
extern const int actor_stat[][13];
|
||||
|
||||
extern const int actor_invstat[][13];
|
||||
|
||||
extern const int16 english_fontCharacterTable[256];
|
||||
extern const int16 german_fontCharacterTable[256];
|
||||
extern const int16 spanish_fontCharacterTable[256];
|
||||
extern const int16 russian_fontCharacterTable[256];
|
||||
|
||||
#define fontCharacterTable (\
|
||||
_vm->getLanguage() == Common::DE_DEU ? german_fontCharacterTable : \
|
||||
_vm->getLanguage() == Common::ES_ESP ? spanish_fontCharacterTable : \
|
||||
_vm->getLanguage() == Common::RU_RUS ? russian_fontCharacterTable : \
|
||||
english_fontCharacterTable)
|
||||
|
||||
// Mouse cursor data
|
||||
extern const byte mouseCursorNormal[];
|
||||
extern const byte mouseCursorDisk[];
|
||||
extern const byte mouseCursorCross[];
|
||||
extern const byte mouseCursorNoMouse[];
|
||||
extern const byte mouseCursorWalk[];
|
||||
extern const byte mouseCursorExit[];
|
||||
extern const byte mouseCursorMagnifyingGlass[];
|
||||
|
||||
// Language strings
|
||||
extern const char *englishLanguageStrings[13];
|
||||
extern const char *frenchLanguageStrings[13];
|
||||
extern const char *germanLanguageStrings[13];
|
||||
extern const char *italianLanguageStrings[13];
|
||||
extern const char *spanishLanguageStrings[13];
|
||||
extern const char *russianLanguageStrings[13];
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
42
engines/cruise/various.cpp
Normal file
42
engines/cruise/various.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
bool remdo = false;
|
||||
bool PCFadeFlag;
|
||||
|
||||
char *getText(int textIndex, int overlayIndex) {
|
||||
if (!overlayTable[overlayIndex].ovlData) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!overlayTable[overlayIndex].ovlData->stringTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return overlayTable[overlayIndex].ovlData->stringTable[textIndex].
|
||||
string;
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
36
engines/cruise/various.h
Normal file
36
engines/cruise/various.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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 CRUISE_VARIOUS_H
|
||||
#define CRUISE_VARIOUS_H
|
||||
|
||||
#include "cruise/cell.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
extern bool remdo;
|
||||
extern bool PCFadeFlag;
|
||||
|
||||
int16 objInit(int ovlIdx, int param1, int param2);
|
||||
char *getText(int textIndex, int overlayIndex);
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
168
engines/cruise/vars.cpp
Normal file
168
engines/cruise/vars.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/* 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 "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
uint8 *_systemFNT = nullptr;
|
||||
|
||||
uint8 itemColor = 1;
|
||||
uint8 selectColor = 3;
|
||||
uint8 titleColor = 2;
|
||||
uint8 subColor = 5;
|
||||
|
||||
int16 scroll;
|
||||
int16 switchPal;
|
||||
char cmdLine[90];
|
||||
|
||||
int16 masterScreen;
|
||||
int16 doFade;
|
||||
int16 fadeFlag = 0;
|
||||
|
||||
preloadStruct preloadData[64];
|
||||
|
||||
volumeDataStruct volumeData[20];
|
||||
|
||||
int32 volumeDataLoaded = 0;
|
||||
|
||||
int16 numOfDisks;
|
||||
|
||||
char lastOverlay[38];
|
||||
char nextOverlay[38];
|
||||
|
||||
int16 currentActiveMenu;
|
||||
int16 autoMsg;
|
||||
menuElementSubStruct* linkedRelation;
|
||||
bool userWait;
|
||||
int16 autoTrack;
|
||||
|
||||
int16 currentDiskNumber = 1;
|
||||
|
||||
int16 volumeNumEntry;
|
||||
fileEntry *volumePtrToFileDescriptor = nullptr;
|
||||
|
||||
uint32 volumeFileDescriptorSize;
|
||||
int16 volumeSizeOfEntry;
|
||||
int16 volumeNumberOfEntry;
|
||||
|
||||
int16 displayOn = 1;
|
||||
|
||||
int16 protectionCode = 0;
|
||||
|
||||
int16 globalVars[2000];
|
||||
|
||||
dataFileEntry filesDatabase[NUM_FILE_ENTRIES];
|
||||
|
||||
int16 bootOverlayNumber;
|
||||
|
||||
SoundEntry soundList[4];
|
||||
|
||||
opcodeTypeFunction opcodeTypeTable[64];
|
||||
|
||||
int16 positionInStack;
|
||||
|
||||
actorStruct actorHead;
|
||||
|
||||
int16 stateID;
|
||||
int16 xdial = 0;
|
||||
|
||||
uint8 *currentData3DataPtr;
|
||||
uint8 *scriptDataPtrTable[7];
|
||||
|
||||
int16 currentScriptOpcodeType;
|
||||
|
||||
int16 saveOpcodeVar;
|
||||
|
||||
int16 narratorOvl = 0;
|
||||
int16 narratorIdx = 0;
|
||||
|
||||
int16 songLoaded;
|
||||
int16 songPlayed;
|
||||
int16 songLoop;
|
||||
int16 activeMouse;
|
||||
int16 userEnabled;
|
||||
int16 var5;
|
||||
int16 dialogueEnabled;
|
||||
int16 dialogueOvl;
|
||||
int16 dialogueObj;
|
||||
int16 userDelay;
|
||||
|
||||
int16 sysKey = -1;
|
||||
int16 sysX = 0;
|
||||
int16 sysY = 0;
|
||||
|
||||
int16 automoveInc;
|
||||
int16 automoveMax;
|
||||
int16 isMessage;
|
||||
int16 automaticMode;
|
||||
int16 aniX;
|
||||
int16 aniY;
|
||||
bool animationStart;
|
||||
|
||||
int16 autoOvl;
|
||||
int16 var39;
|
||||
int16 playerMenuEnabled = 0;
|
||||
int16 var41;
|
||||
int16 var42;
|
||||
int16 var45;
|
||||
int16 var46;
|
||||
int16 var47;
|
||||
int16 var48;
|
||||
int16 flagCt;
|
||||
|
||||
uint8 newPal[NBCOLORS*3];
|
||||
uint8 workpal[NBCOLORS*3];
|
||||
uint8 palScreen[NBSCREENS][NBCOLORS*3];
|
||||
|
||||
//systemStringsStruct systemStrings;
|
||||
|
||||
char currentCtpName[40];
|
||||
|
||||
int16 saveVar1;
|
||||
uint8 saveVar2[97]; // recheck size
|
||||
|
||||
int16 numberOfWalkboxes; // saveVar3
|
||||
int16 walkboxColor[15]; // saveVar4
|
||||
int16 walkboxState[15]; // saveVar5
|
||||
|
||||
uint8 lastAni[16];
|
||||
|
||||
int32 loadFileVar1;
|
||||
|
||||
int16 loadCtFromSave = 0;
|
||||
int16 ctp_routeCoordCount; // ctpVar2
|
||||
int16 ctp_routeCoords[20][2]; // ctpVar3
|
||||
int16 ctp_routes[20][10];
|
||||
int16 ctp_walkboxTable[15][40]; // ctpVar5
|
||||
int16 walkboxColorIndex[16];
|
||||
int16 walkboxZoom[15]; // ctpVar7
|
||||
int16 distanceTable[20][10];
|
||||
|
||||
int16 flagSpeed;
|
||||
int16 speedGame;
|
||||
int16 oldSpeedGame;
|
||||
|
||||
uint8 globalScreen[320 * 200];
|
||||
|
||||
//OSystem *osystem;
|
||||
|
||||
} // End of namespace Cruise
|
||||
290
engines/cruise/vars.h
Normal file
290
engines/cruise/vars.h
Normal file
@@ -0,0 +1,290 @@
|
||||
/* 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 CRUISE_VARS_H
|
||||
#define CRUISE_VARS_H
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
#define NBCOLORS 256
|
||||
#define NBSCREENS 8
|
||||
|
||||
struct menuElementSubStruct {
|
||||
struct menuElementSubStruct *pNext;
|
||||
int16 ovlIdx;
|
||||
int16 header;
|
||||
};
|
||||
|
||||
struct menuElementStruct {
|
||||
struct menuElementStruct *next;
|
||||
const char *string;
|
||||
int x;
|
||||
int y;
|
||||
int varA;
|
||||
bool selected;
|
||||
unsigned char color;
|
||||
gfxEntryStruct *gfx;
|
||||
menuElementSubStruct *ptrSub;
|
||||
};
|
||||
|
||||
typedef int32(*opcodeTypeFunction)();
|
||||
typedef int16(*opcodeFunction)();
|
||||
|
||||
extern uint8 *_systemFNT;
|
||||
extern int16 fontFileIndex;
|
||||
|
||||
extern uint8 itemColor;
|
||||
extern uint8 selectColor;
|
||||
extern uint8 titleColor;
|
||||
extern uint8 subColor;
|
||||
|
||||
extern int16 scroll;
|
||||
extern int16 switchPal;
|
||||
extern char cmdLine[90];
|
||||
|
||||
extern int16 masterScreen;
|
||||
extern int16 doFade;
|
||||
extern int16 fadeFlag;
|
||||
|
||||
struct preloadStruct {
|
||||
char name[15];
|
||||
int32 size;
|
||||
int32 sourceSize;
|
||||
uint8 *ptr;
|
||||
int16 nofree;
|
||||
int16 protect;
|
||||
int16 ovl;
|
||||
};
|
||||
|
||||
struct filesData2Struct {
|
||||
int16 field_0;
|
||||
int16 field_2;
|
||||
};
|
||||
|
||||
struct dataFileName {
|
||||
char name[13];
|
||||
};
|
||||
|
||||
struct setHeaderEntry {
|
||||
int32 offset; // offset ptr
|
||||
int16 width;
|
||||
int16 height;
|
||||
int16 type; // resource type, ie. sprites 0,1,4,5 and 8
|
||||
int16 transparency;
|
||||
int16 hotspotY;
|
||||
int16 hotspotX;
|
||||
};
|
||||
|
||||
struct volumeDataStruct {
|
||||
char ident[10];
|
||||
dataFileName *ptr;
|
||||
int16 diskNumber;
|
||||
int32 size;
|
||||
};
|
||||
|
||||
struct fileEntry {
|
||||
char name[14];
|
||||
int32 offset;
|
||||
int32 size;
|
||||
int32 extSize;
|
||||
int32 unk3; // unused
|
||||
};
|
||||
|
||||
struct dataFileEntrySub {
|
||||
uint8 *ptr;
|
||||
int16 index; // sprite index
|
||||
char name[13];
|
||||
int16 transparency; // sprite transparency
|
||||
uint8 *ptrMask;
|
||||
uint8 resourceType; // sprite and image type 2,4,8 , fnt = 7, spl = 6
|
||||
int16 compression;
|
||||
};
|
||||
|
||||
struct dataFileEntry {
|
||||
uint16 widthInColumn;
|
||||
uint16 width;
|
||||
uint16 resType;
|
||||
uint16 height;
|
||||
dataFileEntrySub subData;
|
||||
};
|
||||
|
||||
struct SoundEntry {
|
||||
int16 frameNum;
|
||||
uint16 frequency;
|
||||
int16 volume;
|
||||
};
|
||||
|
||||
/*
|
||||
struct systemStringsStruct {
|
||||
int8 param;
|
||||
char string[12];
|
||||
char bootScriptName[8];
|
||||
};
|
||||
*/
|
||||
extern preloadStruct preloadData[64];
|
||||
|
||||
extern volumeDataStruct volumeData[20];
|
||||
|
||||
extern int32 volumeDataLoaded;
|
||||
|
||||
extern int16 numOfDisks;
|
||||
|
||||
extern char lastOverlay[38];
|
||||
extern char nextOverlay[38];
|
||||
|
||||
extern int16 currentActiveMenu;
|
||||
extern int16 autoMsg;
|
||||
extern menuElementSubStruct* linkedRelation;
|
||||
extern bool userWait;
|
||||
extern int16 autoTrack;
|
||||
|
||||
extern int16 currentDiskNumber;
|
||||
|
||||
extern int16 volumeNumEntry;
|
||||
extern fileEntry *volumePtrToFileDescriptor;
|
||||
|
||||
extern uint32 volumeFileDescriptorSize;
|
||||
extern int16 volumeSizeOfEntry;
|
||||
extern int16 volumeNumberOfEntry;
|
||||
|
||||
extern int16 displayOn;
|
||||
|
||||
extern int16 protectionCode;
|
||||
|
||||
#define NUM_FILE_ENTRIES 257
|
||||
|
||||
extern int16 globalVars[2000];
|
||||
extern dataFileEntry filesDatabase[NUM_FILE_ENTRIES];
|
||||
|
||||
extern int16 bootOverlayNumber;
|
||||
|
||||
extern SoundEntry soundList[4];
|
||||
|
||||
extern opcodeTypeFunction opcodeTypeTable[64];
|
||||
|
||||
extern int16 positionInStack;
|
||||
extern actorStruct actorHead;
|
||||
|
||||
extern int16 stateID;
|
||||
extern int16 xdial;
|
||||
|
||||
extern uint8 *currentData3DataPtr;
|
||||
extern uint8 *scriptDataPtrTable[7];
|
||||
|
||||
extern int16 currentScriptOpcodeType;
|
||||
|
||||
extern int16 saveOpcodeVar;
|
||||
|
||||
extern int16 narratorOvl;
|
||||
extern int16 narratorIdx;
|
||||
|
||||
extern int16 songLoaded;
|
||||
extern int16 songPlayed;
|
||||
extern int16 songLoop;
|
||||
extern int16 activeMouse;
|
||||
extern int16 userEnabled;
|
||||
extern int16 var5;
|
||||
extern int16 dialogueEnabled;
|
||||
extern int16 dialogueOvl;
|
||||
extern int16 dialogueObj;
|
||||
extern int16 userDelay;
|
||||
extern int16 sysKey;
|
||||
extern int16 sysX;
|
||||
extern int16 sysY;
|
||||
extern int16 automoveInc;
|
||||
extern int16 automoveMax;
|
||||
extern int16 isMessage;
|
||||
extern int16 automaticMode;
|
||||
extern int16 aniX;
|
||||
extern int16 aniY;
|
||||
extern bool animationStart;
|
||||
|
||||
extern int16 autoOvl;
|
||||
extern int16 var39;
|
||||
extern int16 playerMenuEnabled;
|
||||
extern int16 var39;
|
||||
extern int16 var41;
|
||||
extern int16 var42;
|
||||
extern int16 var45;
|
||||
extern int16 var46;
|
||||
extern int16 var47;
|
||||
extern int16 var48;
|
||||
extern int16 flagCt;
|
||||
|
||||
extern uint8 newPal[NBCOLORS*3];
|
||||
extern uint8 workpal[NBCOLORS*3];
|
||||
extern uint8 palScreen[NBSCREENS][NBCOLORS*3];
|
||||
|
||||
//extern systemStringsStruct systemStrings;
|
||||
|
||||
extern char currentCtpName[40];
|
||||
|
||||
extern int16 saveVar1;
|
||||
extern uint8 saveVar2[97]; // recheck size
|
||||
|
||||
extern int16 numberOfWalkboxes; // saveVar3
|
||||
extern int16 walkboxColor[15]; // saveVar4 // Type: 0x00 - non walkable, 0x01 - walkable, 0x02 - exit zone
|
||||
extern int16 walkboxState[15]; // saveVar5 // walkbox can change its type: 0x00 - not changeable, 0x01 - changeable
|
||||
// Assumption: To change the type: walkboxColor[i] -= walkboxChane[i] and vice versa
|
||||
extern uint8 lastAni[16];
|
||||
|
||||
extern int32 loadFileVar1;
|
||||
|
||||
extern int16 loadCtFromSave;
|
||||
extern int16 ctp_routeCoordCount; // ctpVar2 // number of path-finding coordinates
|
||||
extern int16 ctp_routeCoords[20][2]; // ctpVar3 // path-finding coordinates array
|
||||
|
||||
/* ctp_routeCoords:
|
||||
|
||||
correct size would be: ctp_routes[routeCoordCount * 4]
|
||||
coordinate information with x (2 bytes) and y (2 bytes)
|
||||
*/
|
||||
|
||||
extern int16 ctp_routes[20][10]; // path-finding line information
|
||||
|
||||
/* ctp_routes:
|
||||
|
||||
correct size would be: ctp_routes[routeCoordCount * 20 * 2]
|
||||
array is separate in 20 * 2 bytes slices.
|
||||
first 2 bytes of the slice indicate how many coordinates/lines are following (lineCount)
|
||||
after that there are lineCount * 2 bytes following with indexes pointing on the routeCoords table
|
||||
the root x,y for the lines is the coordinate in the routeCoords array, which fits to the current slice
|
||||
for the 20 * i slice the root x,y is routeCoords[i], routeCoords[i+2]
|
||||
the unused rest of the slice if filled up with 0xFF
|
||||
*/
|
||||
extern int16 ctp_walkboxTable[15][40]; // ctpVar5 // walkboxes coordinates and lines
|
||||
extern int16 walkboxColorIndex[16];
|
||||
extern int16 walkboxZoom[15]; // ctpVar7 // scaling information for walkboxes
|
||||
extern int16 distanceTable[20][10];
|
||||
|
||||
extern int16 flagSpeed;
|
||||
extern int16 speedGame;
|
||||
extern int16 oldSpeedGame;
|
||||
|
||||
extern uint8 globalScreen[320 * 200];
|
||||
|
||||
//extern OSystem *osystem;
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
451
engines/cruise/volume.cpp
Normal file
451
engines/cruise/volume.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
/* 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 "cruise/cruise.h"
|
||||
#include "cruise/cruise_main.h"
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
uint8 *PAL_ptr = nullptr;
|
||||
|
||||
int16 numLoadedPal;
|
||||
int16 fileData2;
|
||||
|
||||
char currentBaseName[15] = "";
|
||||
|
||||
void loadPal(volumeDataStruct *entry) {
|
||||
// This code isn't currently being used
|
||||
#if 0
|
||||
char name[20];
|
||||
|
||||
if (_vm->_PAL_file.isOpen())
|
||||
_vm->_PAL_file.close();
|
||||
|
||||
removeExtension(entry->ident, name);
|
||||
strcat(name, ".PAL");
|
||||
|
||||
if (!_vm->_PAL_file.open(name))
|
||||
return;
|
||||
|
||||
numLoadedPal = _vm->_PAL_file.readSint16BE();
|
||||
fileData2 = _vm->_PAL_file.readSint16BE();
|
||||
|
||||
PAL_ptr = (uint8 *)MemAlloc(numLoadedPal * fileData2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void closePal() {
|
||||
if (_vm->_PAL_file.isOpen()) {
|
||||
_vm->_PAL_file.close();
|
||||
|
||||
MemFree(PAL_ptr);
|
||||
PAL_ptr = nullptr;
|
||||
|
||||
numLoadedPal = 0;
|
||||
fileData2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int closeBase() {
|
||||
if (_vm->_currentVolumeFile.isOpen()) {
|
||||
_vm->_currentVolumeFile.close();
|
||||
|
||||
MemFree(volumePtrToFileDescriptor);
|
||||
|
||||
currentBaseName[0] = '\0';
|
||||
}
|
||||
|
||||
if (_vm->_PAL_file.isOpen()) {
|
||||
closePal();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getVolumeDataEntry(volumeDataStruct *entry) {
|
||||
char buffer[256];
|
||||
|
||||
volumeNumEntry = 0;
|
||||
volumeNumberOfEntry = 0;
|
||||
|
||||
if (_vm->_currentVolumeFile.isOpen())
|
||||
freeDisk();
|
||||
|
||||
askDisk(-1);
|
||||
|
||||
Common::strcpy_s(buffer, entry->ident);
|
||||
|
||||
_vm->_currentVolumeFile.open(buffer);
|
||||
|
||||
if (!_vm->_currentVolumeFile.isOpen())
|
||||
return (-14);
|
||||
|
||||
changeCursor(CURSOR_DISK);
|
||||
|
||||
volumeNumberOfEntry = _vm->_currentVolumeFile.readSint16BE();
|
||||
volumeSizeOfEntry = _vm->_currentVolumeFile.readSint16BE();
|
||||
|
||||
volumeNumEntry = volumeNumberOfEntry;
|
||||
|
||||
assert(volumeSizeOfEntry == 14 + 4 + 4 + 4 + 4);
|
||||
|
||||
volumePtrToFileDescriptor = (fileEntry *) mallocAndZero(sizeof(fileEntry) * volumeNumEntry);
|
||||
|
||||
for (int i = 0; i < volumeNumEntry; i++) {
|
||||
volumePtrToFileDescriptor[i].name[0] = 0;
|
||||
volumePtrToFileDescriptor[i].offset = 0;
|
||||
volumePtrToFileDescriptor[i].size = 0;
|
||||
volumePtrToFileDescriptor[i].extSize = 0;
|
||||
volumePtrToFileDescriptor[i].unk3 = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < volumeNumEntry; i++) {
|
||||
_vm->_currentVolumeFile.read(&volumePtrToFileDescriptor[i].name, 14);
|
||||
volumePtrToFileDescriptor[i].offset = _vm->_currentVolumeFile.readSint32BE();
|
||||
volumePtrToFileDescriptor[i].size = _vm->_currentVolumeFile.readSint32BE();
|
||||
volumePtrToFileDescriptor[i].extSize = _vm->_currentVolumeFile.readSint32BE();
|
||||
volumePtrToFileDescriptor[i].unk3 = _vm->_currentVolumeFile.readSint32BE();
|
||||
}
|
||||
|
||||
Common::strcpy_s(currentBaseName, entry->ident);
|
||||
|
||||
loadPal(entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int searchFileInVolCnf(const char *fileName, int32 diskNumber) {
|
||||
int foundDisk = -1;
|
||||
|
||||
for (int i = 0; i < numOfDisks; i++) {
|
||||
if (volumeData[i].diskNumber == diskNumber) {
|
||||
int numOfEntry = volumeData[i].size / 13;
|
||||
|
||||
for (int j = 0; j < numOfEntry; j++) {
|
||||
if (!strcmp(volumeData[i].ptr[j].name, fileName)) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (foundDisk);
|
||||
}
|
||||
|
||||
int32 findFileInDisksSub1(const char *fileName) {
|
||||
int foundDisk = -1;
|
||||
|
||||
for (int i = 0; i < numOfDisks; i++) {
|
||||
int numOfEntry = volumeData[i].size / 13;
|
||||
|
||||
for (int j = 0; j < numOfEntry; j++) {
|
||||
if (!strcmp(volumeData[i].ptr[j].name, fileName)) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (foundDisk);
|
||||
}
|
||||
|
||||
void freeDisk() {
|
||||
if (_vm->_currentVolumeFile.isOpen()) {
|
||||
_vm->_currentVolumeFile.close();
|
||||
MemFree(volumePtrToFileDescriptor);
|
||||
}
|
||||
|
||||
/* TODO
|
||||
* if (PAL_fileHandle)
|
||||
* {
|
||||
* freeAllDataPtr();
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
int16 findFileInList(char *fileName) {
|
||||
if (!_vm->_currentVolumeFile.isOpen())
|
||||
return (-1);
|
||||
|
||||
strToUpper(fileName);
|
||||
|
||||
if (volumeNumEntry <= 0)
|
||||
return (-1);
|
||||
|
||||
for (int i = 0; i < volumeNumEntry; i++) {
|
||||
if (!strcmp(volumePtrToFileDescriptor[i].name, fileName)) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void askDisk(int16 discNumber) {
|
||||
char fileName[256];
|
||||
char string[256];
|
||||
|
||||
if (discNumber != -1) {
|
||||
currentDiskNumber = discNumber;
|
||||
}
|
||||
|
||||
Common::sprintf_s(fileName, "VOL.%d", currentDiskNumber);
|
||||
Common::sprintf_s(string, "INSERER LE DISQUE %d EN ", currentDiskNumber);
|
||||
|
||||
#if 0 // skip drive selection stuff
|
||||
bool messageDrawn = false;
|
||||
while (Common::File::exists((const char*)fileName)) {
|
||||
if (!messageDrawn) {
|
||||
drawMsgString(string);
|
||||
messageDrawn = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
drawMsgString(string);
|
||||
#endif
|
||||
|
||||
changeCursor(currentCursor);
|
||||
}
|
||||
|
||||
int16 findFileInDisks(const char *name) {
|
||||
char fileName[50];
|
||||
int disk;
|
||||
int fileIdx;
|
||||
|
||||
Common::strlcpy(fileName, name, sizeof(fileName));
|
||||
strToUpper(fileName);
|
||||
|
||||
if (!volumeDataLoaded) {
|
||||
debug(1, "CNF wasn't loaded, reading now...");
|
||||
if (_vm->_currentVolumeFile.isOpen()) {
|
||||
askDisk(-1);
|
||||
freeDisk();
|
||||
}
|
||||
|
||||
askDisk(1);
|
||||
readVolCnf();
|
||||
}
|
||||
|
||||
if (_vm->_currentVolumeFile.isOpen()) {
|
||||
askDisk(-1);
|
||||
}
|
||||
|
||||
fileIdx = findFileInList(fileName);
|
||||
|
||||
if (fileIdx >= 0) {
|
||||
return (fileIdx);
|
||||
}
|
||||
|
||||
disk = searchFileInVolCnf(fileName, currentDiskNumber);
|
||||
|
||||
if (disk >= 0) {
|
||||
int temp;
|
||||
|
||||
debug(1, "File found on disk %d", disk);
|
||||
|
||||
if (_vm->_currentVolumeFile.isOpen()) {
|
||||
askDisk(-1);
|
||||
}
|
||||
|
||||
freeDisk();
|
||||
|
||||
askDisk(volumeData[disk].diskNumber);
|
||||
|
||||
getVolumeDataEntry(&volumeData[disk]);
|
||||
|
||||
temp = findFileInList(fileName);
|
||||
|
||||
if (temp >= 0)
|
||||
return (temp);
|
||||
|
||||
return (-1);
|
||||
|
||||
} else {
|
||||
int temp;
|
||||
|
||||
temp = findFileInDisksSub1(fileName);
|
||||
|
||||
if (temp >= 0) {
|
||||
int temp2;
|
||||
|
||||
askDisk(volumeData[temp].diskNumber);
|
||||
|
||||
getVolumeDataEntry(&volumeData[temp]);
|
||||
|
||||
temp2 = findFileInList(fileName);
|
||||
|
||||
if (temp2 >= 0)
|
||||
return (temp2);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
int closeCnf() {
|
||||
for (long int i = 0; i < numOfDisks; i++) {
|
||||
if (volumeData[i].ptr) {
|
||||
MemFree(volumeData[i].ptr);
|
||||
volumeData[i].ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
volumeDataLoaded = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 readVolCnf() {
|
||||
Common::File fileHandle;
|
||||
//short int sizeHEntry;
|
||||
|
||||
volumeDataLoaded = 0;
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
volumeData[i].ident[0] = 0;
|
||||
volumeData[i].ptr = nullptr;
|
||||
volumeData[i].diskNumber = i + 1;
|
||||
volumeData[i].size = 0;
|
||||
}
|
||||
|
||||
fileHandle.open("VOL.CNF");
|
||||
|
||||
if (!fileHandle.isOpen())
|
||||
return (0);
|
||||
|
||||
numOfDisks = fileHandle.readSint16BE();
|
||||
/*sizeHEntry =*/ fileHandle.readSint16BE(); // size of one header entry - 20 bytes
|
||||
|
||||
for (int i = 0; i < numOfDisks; i++) {
|
||||
// fread(&volumeData[i],20,1,fileHandle);
|
||||
fileHandle.read(&volumeData[i].ident, 10);
|
||||
fileHandle.read(&volumeData[i].ptr, 4);
|
||||
volumeData[i].diskNumber = fileHandle.readSint16BE();
|
||||
volumeData[i].size = fileHandle.readSint32BE();
|
||||
|
||||
debug(1, "Disk number: %d", volumeData[i].diskNumber);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numOfDisks; i++) {
|
||||
dataFileName *ptr;
|
||||
|
||||
volumeData[i].size = fileHandle.readSint32BE();
|
||||
|
||||
ptr = (dataFileName *) mallocAndZero(volumeData[i].size);
|
||||
|
||||
volumeData[i].ptr = ptr;
|
||||
|
||||
if (!ptr) {
|
||||
fileHandle.close();
|
||||
return (-2);
|
||||
}
|
||||
|
||||
fileHandle.read(ptr, volumeData[i].size);
|
||||
}
|
||||
|
||||
fileHandle.close();
|
||||
|
||||
volumeDataLoaded = 1;
|
||||
|
||||
//#define dumpResources
|
||||
#ifdef dumpResources
|
||||
|
||||
for (i = 0; i < numOfDisks; i++) {
|
||||
char nameBuffer[256];
|
||||
fileEntry *buffer;
|
||||
|
||||
Common::sprintf_s(nameBuffer, "D%d.", i + 1);
|
||||
|
||||
fileHandle.open(nameBuffer);
|
||||
|
||||
short int numEntry;
|
||||
short int sizeEntry;
|
||||
|
||||
numEntry = fileHandle.readSint16BE();
|
||||
sizeEntry = fileHandle.readSint16BE();
|
||||
|
||||
buffer = (fileEntry *) mallocAndZero(numEntry * sizeEntry);
|
||||
|
||||
for (int j = 0; j < numEntry; j++) {
|
||||
fileHandle.seek(4 + j*0x1E);
|
||||
fileHandle.read(buffer[j].name, 14);
|
||||
buffer[j].offset = fileHandle.readSint32BE();
|
||||
buffer[j].size = fileHandle.readSint32BE();
|
||||
buffer[j].extSize = fileHandle.readSint32BE();
|
||||
buffer[j].unk3 = fileHandle.readSint32BE();
|
||||
|
||||
fileHandle.seek(buffer[j].offset);
|
||||
|
||||
char *bufferLocal;
|
||||
bufferLocal = (char *)mallocAndZero(buffer[j].size);
|
||||
|
||||
fileHandle.read(bufferLocal, buffer[j].size);
|
||||
|
||||
char nameBuffer[256];
|
||||
|
||||
Common::sprintf_s(nameBuffer, "%s", buffer[j].name);
|
||||
|
||||
if (buffer[j].size == buffer[j].extSize) {
|
||||
Common::DumpFile fout;
|
||||
fout.open(nameBuffer);
|
||||
if (fout.isOpen())
|
||||
fout.write(bufferLocal, buffer[j].size);
|
||||
} else {
|
||||
char *uncompBuffer = (char *)mallocAndZero(buffer[j].extSize + 500);
|
||||
|
||||
delphineUnpack((uint8 *) uncompBuffer, (const uint8 *) bufferLocal, buffer[j].size);
|
||||
|
||||
Common::File fout;
|
||||
fout.open(nameBuffer, Common::File::kFileWriteMode);
|
||||
if (fout.isOpen())
|
||||
fout.write(uncompBuffer, buffer[j].extSize);
|
||||
|
||||
//MemFree(uncompBuffer);
|
||||
|
||||
}
|
||||
|
||||
MemFree(bufferLocal);
|
||||
}
|
||||
fileHandle.close();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
///////////////////////////::
|
||||
|
||||
// This code used to rely on "strupr", which is non existent on my system,
|
||||
// thus I just implemented this function instead. - LordHoto
|
||||
//
|
||||
// TODO: This might be code duplication, please check this out.
|
||||
void strToUpper(char *string) {
|
||||
while (*string) {
|
||||
*string = toupper(*string);
|
||||
++string;
|
||||
}
|
||||
}
|
||||
|
||||
void drawMsgString(const char *string) {
|
||||
//printf("%s\n",string);
|
||||
}
|
||||
|
||||
} // End of namespace Cruise
|
||||
44
engines/cruise/volume.h
Normal file
44
engines/cruise/volume.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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 CRUISE_VOLUME_H
|
||||
#define CRUISE_VOLUME_H
|
||||
|
||||
namespace Cruise {
|
||||
|
||||
int16 readVolCnf();
|
||||
int closeCnf();
|
||||
int16 findFileInDisks(const char *name);
|
||||
void freeDisk();
|
||||
int16 findFileInList(const char *fileName);
|
||||
|
||||
////////////////
|
||||
|
||||
void strToUpper(char *string);
|
||||
void drawMsgString(const char *string);
|
||||
void askDisk(int16 discNumber);
|
||||
void setObjectPosition(int16 param1, int16 param2, int16 param3, int16 param4);
|
||||
|
||||
int closeBase();
|
||||
|
||||
} // End of namespace Cruise
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user