Add patch #2846425 - MM C64: walkbox fixed, with minor changes.

svn-id: r45437
This commit is contained in:
Travis Howell 2009-10-27 11:32:33 +00:00
parent 3d80bb47a8
commit 26948eca76
3 changed files with 89 additions and 36 deletions

View File

@ -26,6 +26,7 @@
#include "scumm/scumm.h"
#include "scumm/actor.h"
#include "scumm/boxes.h"
#include "scumm/scumm_v0.h"
#include "scumm/scumm_v6.h"
#include "scumm/util.h"
@ -712,20 +713,19 @@ int ScummEngine::getNextBox(byte from, byte to) {
boxm = getBoxMatrixBaseAddr();
if (_game.version == 0) {
// Skip up to the matrix data for box 'from'
for (i = 0; i < from; i++) {
while (*boxm != 0xFF)
boxm++;
boxm++;
}
// calculate shortest paths
byte *itineraryMatrix = (byte *)malloc(numOfBoxes * numOfBoxes);
calcItineraryMatrix(itineraryMatrix, numOfBoxes);
// Now search for the entry for box 'to'
while (boxm[0] != 0xFF) {
if (boxm[0] == to)
dest = (int8)boxm[0];
boxm++;
}
dest = to;
do {
dest = itineraryMatrix[numOfBoxes * from + dest];
} while (dest != Actor::kInvalidBox && !areBoxesNeighbours(from, dest));
if (dest == Actor::kInvalidBox)
dest = -1;
free(itineraryMatrix);
return dest;
} else if (_game.version <= 2) {
// The v2 box matrix is a real matrix with numOfBoxes rows and columns.
@ -932,7 +932,7 @@ static void printMatrix2(byte *matrix, int num) {
for (i = 0; i < num; i++) {
printf("%2d: ", i);
for (j = 0; j < num; j++) {
int val = matrix[i * 64 + j];
int val = matrix[i * num + j];
if (val == Actor::kInvalidBox)
printf(" ? ");
else
@ -943,17 +943,18 @@ static void printMatrix2(byte *matrix, int num) {
}
#endif
void ScummEngine::createBoxMatrix() {
int num, i, j, k;
byte *adjacentMatrix, *itineraryMatrix;
/**
* Computes shortest paths and stores them in the itinerary matrix.
* Parameter "num" holds the number of rows (= number of columns).
*/
void ScummEngine::calcItineraryMatrix(byte *itineraryMatrix, int num) {
int i, j, k;
byte *adjacentMatrix;
// The total number of boxes
num = getNumBoxes();
assert(num <= 64);
const uint8 boxSize = (_game.version == 0) ? num : 64;
// Allocate the adjacent & itinerary matrices
adjacentMatrix = (byte *)malloc(64 * 64);
itineraryMatrix = (byte *)malloc(64 * 64);
adjacentMatrix = (byte *)malloc(boxSize * boxSize);
// Initialise the adjacent matrix: each box has distance 0 to itself,
// and distance 1 to its direct neighbors. Initially, it has distance
@ -961,14 +962,14 @@ void ScummEngine::createBoxMatrix() {
for (i = 0; i < num; i++) {
for (j = 0; j < num; j++) {
if (i == j) {
adjacentMatrix[i * 64 + j] = 0;
itineraryMatrix[i * 64 + j] = j;
adjacentMatrix[i * boxSize + j] = 0;
itineraryMatrix[i * boxSize + j] = j;
} else if (areBoxesNeighbours(i, j)) {
adjacentMatrix[i * 64 + j] = 1;
itineraryMatrix[i * 64 + j] = j;
adjacentMatrix[i * boxSize + j] = 1;
itineraryMatrix[i * boxSize + j] = j;
} else {
adjacentMatrix[i * 64 + j] = 255;
itineraryMatrix[i * 64 + j] = Actor::kInvalidBox;
adjacentMatrix[i * boxSize + j] = 255;
itineraryMatrix[i * boxSize + j] = Actor::kInvalidBox;
}
}
}
@ -984,17 +985,32 @@ void ScummEngine::createBoxMatrix() {
for (j = 0; j < num; j++) {
if (i == j)
continue;
byte distIK = adjacentMatrix[64 * i + k];
byte distKJ = adjacentMatrix[64 * k + j];
if (adjacentMatrix[64 * i + j] > distIK + distKJ) {
adjacentMatrix[64 * i + j] = distIK + distKJ;
itineraryMatrix[64 * i + j] = itineraryMatrix[64 * i + k];
byte distIK = adjacentMatrix[boxSize * i + k];
byte distKJ = adjacentMatrix[boxSize * k + j];
if (adjacentMatrix[boxSize * i + j] > distIK + distKJ) {
adjacentMatrix[boxSize * i + j] = distIK + distKJ;
itineraryMatrix[boxSize * i + j] = itineraryMatrix[boxSize * i + k];
}
}
}
}
free(adjacentMatrix);
}
void ScummEngine::createBoxMatrix() {
int num, i, j;
// The total number of boxes
num = getNumBoxes();
const uint8 boxSize = (_game.version == 0) ? num : 64;
// calculate shortest paths
byte *itineraryMatrix = (byte *)malloc(boxSize * boxSize);
calcItineraryMatrix(itineraryMatrix, num);
// "Compress" the distance matrix into the box matrix format used
// by the engine. The format is like this:
// For each box (from 0 to num) there is first a byte with value 0xFF,
@ -1015,10 +1031,10 @@ void ScummEngine::createBoxMatrix() {
for (i = 0; i < num; i++) {
addToMatrix(0xFF);
for (j = 0; j < num; j++) {
byte itinerary = itineraryMatrix[64 * i + j];
byte itinerary = itineraryMatrix[boxSize * i + j];
if (itinerary != Actor::kInvalidBox) {
addToMatrix(j);
while (j < num - 1 && itinerary == itineraryMatrix[64 * i + (j + 1)])
while (j < num - 1 && itinerary == itineraryMatrix[boxSize * i + (j + 1)])
j++;
addToMatrix(j);
addToMatrix(itinerary);
@ -1035,7 +1051,6 @@ void ScummEngine::createBoxMatrix() {
printMatrix(getBoxMatrixBaseAddr(), num);
#endif
free(adjacentMatrix);
free(itineraryMatrix);
}
@ -1137,6 +1152,41 @@ bool ScummEngine::areBoxesNeighbours(int box1nr, int box2nr) {
return false;
}
bool ScummEngine_v0::areBoxesNeighbours(int box1nr, int box2nr) {
int i;
const int numOfBoxes = getNumBoxes();
const byte *boxm;
assert(box1nr < numOfBoxes);
assert(box2nr < numOfBoxes);
boxm = getBoxMatrixBaseAddr();
// TODO: what are the first bytes for (mostly 0)?
boxm += 4;
// For each box, the matrix contains an arbitrary number
// of box indices that are linked with the box (neighbors).
// Each list is separated by 0xFF (|).
// E.g. "1 | 0 3 | 3 | 1 2" means:
// 0 -> 1, 1 -> 0/3, 2 -> 3, 3 -> 1/2
// Skip up to the matrix data for box 'box1nr'
for (i = 0; i < box1nr; i++) {
while (*boxm != 0xFF)
boxm++;
boxm++;
}
// Now search for the entry for box 'box2nr'
while (boxm[0] != 0xFF) {
if (boxm[0] == box2nr)
return true;
boxm++;
}
return false;
}
void Actor_v3::findPathTowardsOld(byte box1, byte box2, byte finalBox, Common::Point &p2, Common::Point &p3) {
Common::Point gateA[2];
Common::Point gateB[2];

View File

@ -1181,8 +1181,9 @@ protected:
void setBoxScaleSlot(int box, int slot);
void convertScaleTableToScaleSlot(int slot);
void calcItineraryMatrix(byte *itineraryMatrix, int num);
void createBoxMatrix();
bool areBoxesNeighbours(int i, int j);
virtual bool areBoxesNeighbours(int i, int j);
/* String class */
public:

View File

@ -96,6 +96,8 @@ protected:
virtual void resetSentence(bool walking = false);
virtual bool areBoxesNeighbours(int box1nr, int box2nr);
/* Version C64 script opcodes */
void o_stopCurrentScript();
void o_loadSound();