Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

1
engines/cruise/POTFILES Normal file
View File

@@ -0,0 +1 @@
engines/cruise/metaengine.cpp

926
engines/cruise/actor.cpp Normal file
View 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, &params);
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
View 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

View 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

View 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

View 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, &params);
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, &params);
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, &params);
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

View 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
View 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
View 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

View 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

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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

View 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

View 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
View 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, &params);
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
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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);

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

38
engines/cruise/function.h Normal file
View 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

View 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

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

48
engines/cruise/mainDraw.h Normal file
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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, &note, &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
View 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
View 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
View 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

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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