Ticket #9074: mm64-walkbox.patch

File mm64-walkbox.patch, 6.5 KB (added by SF/tobigun, 13 years ago)

MM C64 walkbox fix

  • engines/scumm/boxes.cpp

     
    2626#include "scumm/scumm.h"
    2727#include "scumm/actor.h"
    2828#include "scumm/boxes.h"
     29#include "scumm/scumm_v0.h"
    2930#include "scumm/scumm_v6.h"
    3031#include "scumm/util.h"
    3132
     
    712713        boxm = getBoxMatrixBaseAddr();
    713714
    714715        if (_game.version == 0) {
    715                 // Skip up to the matrix data for box 'from'
    716                 for (i = 0; i < from; i++) {
    717                         while (*boxm != 0xFF)
    718                                 boxm++;
    719                         boxm++;
    720                 }
     716                // calculate shortest paths
     717                byte *itineraryMatrix = (byte *)malloc(numOfBoxes * numOfBoxes);
     718                calcItineraryMatrix(itineraryMatrix, numOfBoxes);
    721719
    722                 // Now search for the entry for box 'to'
    723                 while (boxm[0] != 0xFF) {
    724                         if (boxm[0] == to)
    725                                 dest = (int8)boxm[0];
    726                         boxm++;
    727                 }
     720                dest = to;
     721                do {
     722                        dest = itineraryMatrix[numOfBoxes * from + dest];
     723                } while (dest != Actor::kInvalidBox && !areBoxesNeighbours(from, dest));
    728724
     725                if (dest == Actor::kInvalidBox)
     726                        dest = -1;
     727
     728                free(itineraryMatrix);
    729729                return dest;
    730730        } else if (_game.version <= 2) {
    731731                // The v2 box matrix is a real matrix with numOfBoxes rows and columns.
     
    932932        for (i = 0; i < num; i++) {
    933933                printf("%2d: ", i);
    934934                for (j = 0; j < num; j++) {
    935                         int val = matrix[i * 64 + j];
     935                        int val = matrix[i * num + j];
    936936                        if (val == Actor::kInvalidBox)
    937937                                printf(" ? ");
    938938                        else
     
    943943}
    944944#endif
    945945
    946 void ScummEngine::createBoxMatrix() {
    947         int num, i, j, k;
    948         byte *adjacentMatrix, *itineraryMatrix;
     946/**
     947 * Computes shortest paths and stores them in the itinerary matrix.
     948 * Parameter "num" holds the number of rows (= number of columns).
     949 */
     950void ScummEngine::calcItineraryMatrix(byte *itineraryMatrix, int num) {
     951        int i, j, k;
     952        byte *adjacentMatrix;
    949953
    950         // The total number of boxes
    951         num = getNumBoxes();
    952         assert(num <= 64);
    953 
    954954        // Allocate the adjacent & itinerary matrices
    955         adjacentMatrix = (byte *)malloc(64 * 64);
    956         itineraryMatrix = (byte *)malloc(64 * 64);
     955        adjacentMatrix = (byte *)malloc(num * num);
    957956
    958957        // Initialise the adjacent matrix: each box has distance 0 to itself,
    959958        // and distance 1 to its direct neighbors. Initially, it has distance
     
    961960        for (i = 0; i < num; i++) {
    962961                for (j = 0; j < num; j++) {
    963962                        if (i == j) {
    964                                 adjacentMatrix[i * 64 + j] = 0;
    965                                 itineraryMatrix[i * 64 + j] = j;
     963                                adjacentMatrix[i * num + j] = 0;
     964                                itineraryMatrix[i * num + j] = j;
    966965                        } else if (areBoxesNeighbours(i, j)) {
    967                                 adjacentMatrix[i * 64 + j] = 1;
    968                                 itineraryMatrix[i * 64 + j] = j;
     966                                adjacentMatrix[i * num + j] = 1;
     967                                itineraryMatrix[i * num + j] = j;
    969968                        } else {
    970                                 adjacentMatrix[i * 64 + j] = 255;
    971                                 itineraryMatrix[i * 64 + j] = Actor::kInvalidBox;
     969                                adjacentMatrix[i * num + j] = 255;
     970                                itineraryMatrix[i * num + j] = Actor::kInvalidBox;
    972971                        }
    973972                }
    974973        }
     
    984983                        for (j = 0; j < num; j++) {
    985984                                if (i == j)
    986985                                        continue;
    987                                 byte distIK = adjacentMatrix[64 * i + k];
    988                                 byte distKJ = adjacentMatrix[64 * k + j];
    989                                 if (adjacentMatrix[64 * i + j] > distIK + distKJ) {
    990                                         adjacentMatrix[64 * i + j] = distIK + distKJ;
    991                                         itineraryMatrix[64 * i + j] = itineraryMatrix[64 * i + k];
     986                                byte distIK = adjacentMatrix[num * i + k];
     987                                byte distKJ = adjacentMatrix[num * k + j];
     988                                if (adjacentMatrix[num * i + j] > distIK + distKJ) {
     989                                        adjacentMatrix[num * i + j] = distIK + distKJ;
     990                                        itineraryMatrix[num * i + j] = itineraryMatrix[num * i + k];
    992991                                }
    993992                        }
    994993                }
    995994
    996995        }
    997996
     997        free(adjacentMatrix);
     998}
     999
     1000void ScummEngine::createBoxMatrix() {
     1001        int num, i, j;
     1002
     1003        // The total number of boxes
     1004        num = getNumBoxes();
     1005
     1006        // calculate shortest paths
     1007        byte *itineraryMatrix = (byte *)malloc(num * num);
     1008        calcItineraryMatrix(itineraryMatrix, num);
     1009
    9981010        // "Compress" the distance matrix into the box matrix format used
    9991011        // by the engine. The format is like this:
    10001012        // For each box (from 0 to num) there is first a byte with value 0xFF,
     
    10151027        for (i = 0; i < num; i++) {
    10161028                addToMatrix(0xFF);
    10171029                for (j = 0; j < num; j++) {
    1018                         byte itinerary = itineraryMatrix[64 * i + j];
     1030                        byte itinerary = itineraryMatrix[num * i + j];
    10191031                        if (itinerary != Actor::kInvalidBox) {
    10201032                                addToMatrix(j);
    1021                                 while (j < num - 1 && itinerary == itineraryMatrix[64 * i + (j + 1)])
     1033                                while (j < num - 1 && itinerary == itineraryMatrix[num * i + (j + 1)])
    10221034                                        j++;
    10231035                                addToMatrix(j);
    10241036                                addToMatrix(itinerary);
     
    10351047        printMatrix(getBoxMatrixBaseAddr(), num);
    10361048#endif
    10371049
    1038         free(adjacentMatrix);
    10391050        free(itineraryMatrix);
    10401051}
    10411052
     
    11371148        return false;
    11381149}
    11391150
     1151bool ScummEngine_v0::areBoxesNeighbours(int box1nr, int box2nr) {
     1152        int i;
     1153        const int numOfBoxes = getNumBoxes();
     1154        const byte *boxm;
     1155
     1156        assert(box1nr < numOfBoxes);
     1157        assert(box2nr < numOfBoxes);
     1158
     1159        boxm = getBoxMatrixBaseAddr();
     1160        // TODO: what are the first bytes for (mostly 0)?
     1161        boxm += 4;
     1162
     1163        // For each box, the matrix contains an arbitrary number
     1164        // of box indices that are linked with the box (neighbors).
     1165        // Each list is separated by 0xFF (|).
     1166        // E.g. "1 | 0 3 | 3 | 1 2" means:
     1167        //   0 -> 1, 1 -> 0/3, 2 -> 3, 3 -> 1/2
     1168
     1169        // Skip up to the matrix data for box 'box1nr'
     1170        for (i = 0; i < box1nr; i++) {
     1171                while (*boxm != 0xFF)
     1172                        boxm++;
     1173                boxm++;
     1174        }
     1175
     1176        // Now search for the entry for box 'box2nr'
     1177        while (boxm[0] != 0xFF) {
     1178                if (boxm[0] == box2nr)
     1179                        return true;
     1180                boxm++;
     1181        }
     1182
     1183        return false;
     1184}
     1185
    11401186void Actor_v3::findPathTowardsOld(byte box1, byte box2, byte finalBox, Common::Point &p2, Common::Point &p3) {
    11411187        Common::Point pt;
    11421188        Common::Point gateA[2];
  • engines/scumm/scumm.h

     
    11781178        void setBoxScaleSlot(int box, int slot);
    11791179        void convertScaleTableToScaleSlot(int slot);
    11801180
     1181        void calcItineraryMatrix(byte *itineraryMatrix, int num);
    11811182        void createBoxMatrix();
    1182         bool areBoxesNeighbours(int i, int j);
     1183        virtual bool areBoxesNeighbours(int i, int j);
    11831184
    11841185        /* String class */
    11851186public:
  • engines/scumm/scumm_v0.h

     
    9696
    9797        virtual void resetSentence(bool walking = false);
    9898
     99        virtual bool areBoxesNeighbours(int box1nr, int box2nr);
     100
    99101        /* Version C64 script opcodes */
    100102        void o_stopCurrentScript();
    101103        void o_loadSound();