mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-02 15:16:46 +00:00
cleaned up autoroute code
svn-id: r9318
This commit is contained in:
parent
e5343ac038
commit
c9f060573f
@ -26,354 +26,238 @@
|
||||
#define ROUTE_GRID_SIZE (ROUTE_GRID_WIDTH*ROUTE_GRID_HEIGHT*2)
|
||||
#define WALK_JUMP 8 // walk in blocks of 8
|
||||
|
||||
const int16 SkyAutoRoute::_routeDirections[4] = { -1, 1, -ROUTE_GRID_WIDTH, ROUTE_GRID_WIDTH };
|
||||
const uint16 SkyAutoRoute::_logicCommands[4] = { RIGHTY, LEFTY, DOWNY, UPY };
|
||||
|
||||
SkyAutoRoute::SkyAutoRoute(SkyGrid *pGrid) {
|
||||
|
||||
_grid = pGrid;
|
||||
_routeGrid = (uint16 *)malloc(ROUTE_GRID_SIZE);
|
||||
_routeBuf = (uint16 *)malloc(ROUTE_SPACE);
|
||||
}
|
||||
|
||||
SkyAutoRoute::~SkyAutoRoute(void) {
|
||||
|
||||
free(_routeGrid);
|
||||
free(_routeBuf);
|
||||
}
|
||||
|
||||
uint16 SkyAutoRoute::checkBlock(uint16 *blockPos) {
|
||||
|
||||
uint16 fieldVal, retVal = 0xFFFF;
|
||||
fieldVal = blockPos[1]; // field to the right
|
||||
if ((!(fieldVal & 0x8000)) && (fieldVal != 0)) retVal = fieldVal;
|
||||
fieldVal = (blockPos - 1)[0]; // field to the left
|
||||
if ((!(fieldVal & 0x8000)) && (fieldVal != 0)) {
|
||||
if ((fieldVal < retVal) || (retVal == 0xFFFF)) retVal = fieldVal;
|
||||
}
|
||||
fieldVal = (blockPos + ROUTE_GRID_WIDTH)[0]; // upper field
|
||||
if ((!(fieldVal & 0x8000)) && (fieldVal != 0)) {
|
||||
if ((fieldVal < retVal) || (retVal == 0xFFFF)) retVal = fieldVal;
|
||||
}
|
||||
fieldVal = (blockPos - ROUTE_GRID_WIDTH)[0]; // upper field
|
||||
if ((!(fieldVal & 0x8000)) && (fieldVal != 0)) {
|
||||
if ((fieldVal < retVal) || (retVal == 0xFFFF)) retVal = fieldVal;
|
||||
uint16 retVal = 0xFFFF;
|
||||
|
||||
for (uint8 cnt = 0; cnt < 4; cnt++) {
|
||||
uint16 fieldVal = *(blockPos + _routeDirections[cnt]);
|
||||
if (fieldVal && (fieldVal < retVal))
|
||||
retVal = fieldVal;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#undef ARDEBUG
|
||||
|
||||
uint16 SkyAutoRoute::autoRoute(Compact *cpt, uint16 **pSaveRoute) {
|
||||
|
||||
if (!cpt->extCompact)
|
||||
error("SkyAutoRoute::autoRoute: fatal error. cpt->extCompact == NULL");
|
||||
uint16* routeData = (uint16 *)cpt->extCompact->animScratch;
|
||||
uint8* screenGrid = _grid->giveGrid(cpt->screen);
|
||||
screenGrid += GRID_SIZE-4; // all arrays are processed from behind, so make
|
||||
// screenGrid point to the last element of our grid.
|
||||
|
||||
uint16 *routeCalc = _routeGrid + (ROUTE_GRID_SIZE >> 1) - ROUTE_GRID_WIDTH - 2;
|
||||
|
||||
uint8 stretch1, stretch2; // bl / bh
|
||||
stretch1 = 0;
|
||||
MegaSet *mega = SkyCompact::getMegaSet(cpt, cpt->extCompact->megaSet);
|
||||
stretch2 = (uint8)(mega->gridWidth & 0xff);
|
||||
|
||||
uint16 cnt;
|
||||
//First clear the bottom line and right hand edge of next line
|
||||
for (cnt = 0; cnt < ROUTE_GRID_WIDTH + 1; cnt++)
|
||||
_routeGrid[(ROUTE_GRID_SIZE >> 1) - 1 - cnt] = 0;
|
||||
|
||||
uint16 gridCntX = ROUTE_GRID_WIDTH - 2; // ch
|
||||
uint16 gridCntY = ROUTE_GRID_HEIGHT - 2; // ebp
|
||||
uint16 bitsLeft = 32;
|
||||
uint32 gridData = screenGrid[0] | (screenGrid[1] << 8) |
|
||||
(screenGrid[2] << 16) | (screenGrid[3] << 24);
|
||||
screenGrid -= 4;
|
||||
do {
|
||||
//stretch:
|
||||
uint8 shiftBit = (uint8)gridData&1;
|
||||
gridData >>= 1;
|
||||
if (shiftBit) {
|
||||
//bit_set:
|
||||
routeCalc[0] = 0xFFFF;
|
||||
stretch1 = stretch2; // set up stretch factor
|
||||
} else {
|
||||
if (stretch1) {
|
||||
//still_stretching:
|
||||
stretch1--;
|
||||
routeCalc[0] = 0xFFFF;
|
||||
} else {
|
||||
routeCalc[0] = 0; // this block is free
|
||||
}
|
||||
}
|
||||
// next_stretch:
|
||||
routeCalc--;
|
||||
bitsLeft--;
|
||||
// still bits:
|
||||
gridCntX--;
|
||||
if (gridCntX == 0) {
|
||||
routeCalc--;
|
||||
routeCalc[0] = routeCalc[1] = 0; // do edges
|
||||
routeCalc--;
|
||||
gridCntX = ROUTE_GRID_WIDTH - 2;
|
||||
stretch1 = 0; // clear stretch factor
|
||||
gridCntY--;
|
||||
}
|
||||
if (gridCntY && (!bitsLeft)) {
|
||||
gridData = screenGrid[0] | (screenGrid[1] << 8) |
|
||||
(screenGrid[2] << 16) | (screenGrid[3] << 24);
|
||||
screenGrid -= 4;
|
||||
bitsLeft = 32;
|
||||
}
|
||||
} while(gridCntY);
|
||||
for (cnt = 0; cnt < ROUTE_GRID_WIDTH - 1; cnt++)
|
||||
_routeGrid[cnt] = 0; // clear top line (right hand edge already done
|
||||
|
||||
// the grid has been initialised
|
||||
|
||||
// calculate start and end points
|
||||
int16 initX = 0, initY = 0, postX = 0, postY = 0;
|
||||
uint8 initBlockY; // bh
|
||||
uint8 initBlockX; // bl
|
||||
uint8 postBlockY; // ch
|
||||
uint8 postBlockX; // cl
|
||||
|
||||
if (cpt->ycood < TOP_LEFT_Y) {
|
||||
initY = cpt->ycood - TOP_LEFT_Y;
|
||||
initBlockY = 0;
|
||||
} else if (cpt->ycood - TOP_LEFT_Y >= GAME_SCREEN_HEIGHT) { // no_init_y1
|
||||
initY = cpt->ycood - TOP_LEFT_Y - GAME_SCREEN_HEIGHT;
|
||||
initBlockY = (GAME_SCREEN_HEIGHT - 1) >> 3; // convert to blocks
|
||||
} else { // no_init_y2
|
||||
initBlockY = (cpt->ycood - TOP_LEFT_Y) >> 3; // convert to blocks
|
||||
}
|
||||
|
||||
if (cpt->xcood < TOP_LEFT_X) {
|
||||
initX = cpt->xcood - TOP_LEFT_X;
|
||||
initBlockX = 0;
|
||||
} else if (cpt->xcood - TOP_LEFT_X >= GAME_SCREEN_WIDTH) { // no_init_x1
|
||||
initX = cpt->xcood - TOP_LEFT_X - (GAME_SCREEN_WIDTH - 1); // -1 to match amiga
|
||||
initBlockX = (GAME_SCREEN_WIDTH - 1) >> 3;
|
||||
} else { // no_init_x2
|
||||
initBlockX = (cpt->xcood - TOP_LEFT_X) >> 3;
|
||||
}
|
||||
|
||||
// destination coords:
|
||||
|
||||
if (cpt->extCompact->arTargetY < TOP_LEFT_Y) {
|
||||
postY = cpt->extCompact->arTargetY - TOP_LEFT_Y;
|
||||
postBlockY = 0;
|
||||
} else if (cpt->extCompact->arTargetY - TOP_LEFT_Y >= GAME_SCREEN_HEIGHT) { // no_post_y1
|
||||
postY = cpt->extCompact->arTargetY - TOP_LEFT_Y - (GAME_SCREEN_HEIGHT - 1);
|
||||
postBlockY = (GAME_SCREEN_HEIGHT - 1) >> 3;
|
||||
} else { // no_post_y2
|
||||
postBlockY = (cpt->extCompact->arTargetY - TOP_LEFT_Y) >> 3;
|
||||
}
|
||||
|
||||
if (cpt->extCompact->arTargetX < TOP_LEFT_X) {
|
||||
postX = cpt->extCompact->arTargetX - TOP_LEFT_X;
|
||||
postBlockX = 0;
|
||||
} else if (cpt->extCompact->arTargetX - TOP_LEFT_X >= GAME_SCREEN_WIDTH) {
|
||||
postX = cpt->extCompact->arTargetX - TOP_LEFT_X - (GAME_SCREEN_WIDTH - 1);
|
||||
postBlockX = (GAME_SCREEN_WIDTH - 1) >> 3;
|
||||
void SkyAutoRoute::clipCoordX(uint16 x, uint8 &blkX, int16 &initX) {
|
||||
if (x < TOP_LEFT_X) {
|
||||
blkX = 0;
|
||||
initX = x - TOP_LEFT_X;
|
||||
} else if (x >= TOP_LEFT_X + GAME_SCREEN_WIDTH) {
|
||||
blkX = (GAME_SCREEN_WIDTH - 1) >> 3;
|
||||
initX = x - (TOP_LEFT_X + GAME_SCREEN_WIDTH);
|
||||
} else {
|
||||
postBlockX = (cpt->extCompact->arTargetX - TOP_LEFT_X) >> 3;
|
||||
}
|
||||
if ((postBlockX == initBlockX) && (postBlockY == initBlockY)) {
|
||||
// empty route
|
||||
routeData[0] = 0;
|
||||
return 1;
|
||||
blkX = (x - TOP_LEFT_X) >> 3;
|
||||
initX = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32 directionX, directionY;
|
||||
uint8 numLines, numCols; // number of lines / columns to go
|
||||
if (initBlockY > postBlockY) {
|
||||
directionY = -ROUTE_GRID_WIDTH;
|
||||
numLines = initBlockY;
|
||||
} else { // go_down:
|
||||
directionY = ROUTE_GRID_WIDTH;
|
||||
numLines = (ROUTE_GRID_HEIGHT-1)-initBlockY;
|
||||
void SkyAutoRoute::clipCoordY(uint16 y, uint8 &blkY, int16 &initY) {
|
||||
if (y < TOP_LEFT_Y) {
|
||||
blkY = 0;
|
||||
initY = y - TOP_LEFT_Y;
|
||||
} else if (y >= TOP_LEFT_Y + GAME_SCREEN_HEIGHT) {
|
||||
blkY = (GAME_SCREEN_HEIGHT - 1) >> 3;
|
||||
initY = y - (TOP_LEFT_Y + GAME_SCREEN_WIDTH);
|
||||
} else {
|
||||
blkY = (y - TOP_LEFT_Y) >> 3;
|
||||
initY = 0;
|
||||
}
|
||||
if (initBlockX > postBlockX) {
|
||||
}
|
||||
|
||||
void SkyAutoRoute::initWalkGrid(uint8 screen, uint8 width) {
|
||||
|
||||
uint16 *wGridPos;
|
||||
uint8 stretch = 0;
|
||||
uint8 *screenGrid = _grid->giveGrid(screen);
|
||||
screenGrid += GRID_SIZE;
|
||||
wGridPos = _routeGrid + (ROUTE_GRID_SIZE >> 1) - ROUTE_GRID_WIDTH - 2;
|
||||
|
||||
memset(_routeGrid, 0, ROUTE_GRID_SIZE);
|
||||
uint8 bitsLeft = 0; uint32 gridData = 0;
|
||||
for (uint8 gridCntY = 0; gridCntY < ROUTE_GRID_HEIGHT - 2; gridCntY++) {
|
||||
for (uint8 gridCntX = 0; gridCntX < ROUTE_GRID_WIDTH - 2; gridCntX++) {
|
||||
if (!bitsLeft) {
|
||||
screenGrid -= 4;
|
||||
gridData = READ_LE_UINT32(screenGrid);
|
||||
bitsLeft = 32;
|
||||
}
|
||||
if (gridData & 1) {
|
||||
*wGridPos = 0xFFFF; // block is not accessible
|
||||
stretch = width;
|
||||
} else if (stretch) {
|
||||
*wGridPos = 0xFFFF;
|
||||
stretch--;
|
||||
}
|
||||
wGridPos--;
|
||||
bitsLeft--;
|
||||
gridData >>= 1;
|
||||
}
|
||||
wGridPos -= 2;
|
||||
stretch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkyAutoRoute::calcWalkGrid(uint8 startX, uint8 startY, uint8 destX, uint8 destY) {
|
||||
|
||||
int16 directionX, directionY;
|
||||
uint8 roiX, roiY; // Rectangle Of Interest in the walk grid
|
||||
if (startY > destY) {
|
||||
directionY = -ROUTE_GRID_WIDTH;
|
||||
roiY = startY;
|
||||
} else {
|
||||
directionY = ROUTE_GRID_WIDTH;
|
||||
roiY = (ROUTE_GRID_HEIGHT-1) - startY;
|
||||
}
|
||||
if (startX > destX) {
|
||||
directionX = -1;
|
||||
numCols = initBlockX+2;
|
||||
roiX = startX + 2;
|
||||
} else {
|
||||
directionX = 1;
|
||||
numCols = (ROUTE_GRID_WIDTH - 1) - initBlockX;
|
||||
roiX = (ROUTE_GRID_WIDTH - 1) - startX;
|
||||
}
|
||||
// calculate destination address
|
||||
uint16 *routeDestCalc;
|
||||
routeDestCalc = (postBlockY + 1) * ROUTE_GRID_WIDTH + postBlockX + 1 + _routeGrid;
|
||||
|
||||
uint16 *routeSrcCalc;
|
||||
routeSrcCalc = (initBlockY + 1) * ROUTE_GRID_WIDTH + initBlockX + 1 + _routeGrid;
|
||||
routeSrcCalc[0] = 1; //start this one off
|
||||
// means: mark the block we start from as accessible
|
||||
#ifdef ARDEBUG
|
||||
uint16 dcnt1, dcnt2;
|
||||
for (dcnt1 = 0; dcnt1 < ROUTE_GRID_HEIGHT; dcnt1++) {
|
||||
for (dcnt2 = 0; dcnt2 < ROUTE_GRID_WIDTH; dcnt2++) {
|
||||
if (!_routeGrid[dcnt1*ROUTE_GRID_WIDTH + dcnt2]) printf("_");
|
||||
else if (_routeGrid[dcnt1*ROUTE_GRID_WIDTH + dcnt2] == 1) printf("S");
|
||||
else printf("X");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
getchar();
|
||||
#endif
|
||||
uint16 *walkDest = _routeGrid + (destY + 1) * ROUTE_GRID_WIDTH + destX + 1;
|
||||
uint16 *walkStart = _routeGrid + (startY + 1) * ROUTE_GRID_WIDTH + startX + 1;
|
||||
*walkStart = 1;
|
||||
uint16 *walkPos = walkStart;
|
||||
|
||||
// if we are on the edge, move diagonally from start
|
||||
if (numLines < ROUTE_GRID_HEIGHT-3)
|
||||
routeSrcCalc -= directionY;
|
||||
if (roiY < ROUTE_GRID_HEIGHT-3)
|
||||
walkStart -= directionY;
|
||||
|
||||
if (numCols < ROUTE_GRID_WIDTH-2)
|
||||
routeSrcCalc -= directionX;
|
||||
if (roiX < ROUTE_GRID_WIDTH-2)
|
||||
walkStart -= directionX;
|
||||
|
||||
bool gridChanged = true;
|
||||
bool foundRoute = false;
|
||||
|
||||
if (routeDestCalc[0]) {
|
||||
// If destination is a wall then we have no route
|
||||
// By the way, we could improve this algorithm by moving as close to the
|
||||
// wall as possible. The original pathfinding of SKY sucked, if I remember correctly
|
||||
return 2;
|
||||
}
|
||||
uint8 cnty; // ch
|
||||
uint8 cntx; // cl
|
||||
// numLines = dh, numCols = dl
|
||||
uint16 blockRet;
|
||||
bool gridChanged, foundRoute;
|
||||
do { // wallow_y
|
||||
while ((!foundRoute) && gridChanged) {
|
||||
gridChanged = false;
|
||||
cnty = numLines;
|
||||
uint16 *yPushedSrc = routeSrcCalc;
|
||||
do { // wallow_x
|
||||
cntx = numCols;
|
||||
uint16 *xPushedSrc = routeSrcCalc;
|
||||
do { // wallow
|
||||
if (!routeSrcCalc[0]) {
|
||||
// block wasn't yet done
|
||||
blockRet = checkBlock(routeSrcCalc);
|
||||
if (blockRet != 0xFFFF) {
|
||||
// this block is accessible
|
||||
routeSrcCalc[0] = blockRet+1;
|
||||
uint16 *yWalkCalc = walkStart;
|
||||
for (uint8 cnty = 0; cnty < roiY; cnty++) {
|
||||
uint16 *xWalkCalc = yWalkCalc;
|
||||
for (uint8 cntx = 0; cntx < roiX; cntx++) {
|
||||
if (!*xWalkCalc) { // block wasn't done, yet
|
||||
uint16 blockRet = checkBlock(xWalkCalc);
|
||||
if (blockRet < 0xFFFF) {
|
||||
*xWalkCalc = blockRet + 1;
|
||||
gridChanged = true;
|
||||
}
|
||||
}
|
||||
routeSrcCalc += directionX;
|
||||
cntx--;
|
||||
} while (cntx);
|
||||
routeSrcCalc = xPushedSrc + directionY;
|
||||
cnty--;
|
||||
} while (cnty);
|
||||
routeSrcCalc = yPushedSrc;
|
||||
|
||||
foundRoute = false;
|
||||
if (!routeDestCalc[0]) {
|
||||
// we have done a section, see if we want to shift backwards (what?)
|
||||
if (numLines < ROUTE_GRID_HEIGHT - 4) {
|
||||
routeSrcCalc -= directionY;
|
||||
numLines++;
|
||||
xWalkCalc += directionX;
|
||||
}
|
||||
if (numCols < ROUTE_GRID_WIDTH - 4) {
|
||||
routeSrcCalc -= directionX;
|
||||
numCols++;
|
||||
}
|
||||
} else foundRoute = true;
|
||||
} while ((!foundRoute) && gridChanged);
|
||||
#ifdef ARDEBUG
|
||||
for (dcnt1 = 0; dcnt1 < ROUTE_GRID_HEIGHT; dcnt1++) {
|
||||
for (dcnt2 = 0; dcnt2 < ROUTE_GRID_WIDTH; dcnt2++) {
|
||||
printf(" %02X",_routeGrid[dcnt1*ROUTE_GRID_WIDTH + dcnt2]&0xFF);
|
||||
yWalkCalc += directionY;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
if (!routeDestCalc[0]) {
|
||||
// no route exists from routeSrc to routeDest
|
||||
return 2;
|
||||
}
|
||||
// ok, we know now that it's possible to get from the start position to the desired
|
||||
// destination. Let's see how.
|
||||
uint16 *saveRoute = routeData + (ROUTE_SPACE >> 1) - 1; // route_space is given in bytes so >> 1
|
||||
saveRoute[0] = 0; // route is null terminated
|
||||
uint16 lastVal;
|
||||
lastVal = routeDestCalc[0];
|
||||
lastVal--;
|
||||
bool routeDone = false;
|
||||
do {
|
||||
// check_dir:
|
||||
if (lastVal == (routeDestCalc-1)[0]) {
|
||||
// look_left
|
||||
saveRoute -= 2;
|
||||
saveRoute[1] = RIGHTY;
|
||||
saveRoute[0] = 0;
|
||||
while ((lastVal == (routeDestCalc-1)[0]) && (!routeDone)) {
|
||||
routeDestCalc--; // keep checking left
|
||||
saveRoute[0] += WALK_JUMP;
|
||||
#ifdef ARDEBUG
|
||||
printf("left\n");
|
||||
#endif
|
||||
lastVal--;
|
||||
if (lastVal == 0) routeDone = true;
|
||||
if (*walkDest) { // okay, finished
|
||||
foundRoute = true;
|
||||
} else { // we couldn't find the route, let's extend the ROI
|
||||
if (roiY < ROUTE_GRID_HEIGHT - 4) {
|
||||
walkStart -= directionY;
|
||||
roiY++;
|
||||
}
|
||||
} else if (lastVal == routeDestCalc[1]) {
|
||||
// look_right
|
||||
saveRoute -= 2;
|
||||
saveRoute[1] = LEFTY;
|
||||
saveRoute[0] = 0;
|
||||
while ((lastVal == routeDestCalc[1]) && (!routeDone)) {
|
||||
routeDestCalc++; // keep checking right
|
||||
saveRoute[0] += WALK_JUMP;
|
||||
#ifdef ARDEBUG
|
||||
printf("right\n");
|
||||
#endif
|
||||
lastVal--;
|
||||
if (lastVal == 0) routeDone = true;
|
||||
if (roiX < ROUTE_GRID_WIDTH - 4) {
|
||||
walkStart -= directionX;
|
||||
roiX++;
|
||||
}
|
||||
} else if (lastVal == (routeDestCalc - ROUTE_GRID_WIDTH)[0]) {
|
||||
// look_up
|
||||
saveRoute -= 2;
|
||||
saveRoute[1] = DOWNY;
|
||||
saveRoute[0] = 0;
|
||||
while ((lastVal == (routeDestCalc - ROUTE_GRID_WIDTH)[0]) && (!routeDone)) {
|
||||
routeDestCalc -= ROUTE_GRID_WIDTH; // keep checking up
|
||||
saveRoute[0] += WALK_JUMP;
|
||||
#ifdef ARDEBUG
|
||||
printf("up\n");
|
||||
#endif
|
||||
lastVal--;
|
||||
if (lastVal == 0) routeDone = true;
|
||||
}
|
||||
} else if (lastVal == (routeDestCalc + ROUTE_GRID_WIDTH)[0]) {
|
||||
// look_down
|
||||
saveRoute -= 2;
|
||||
saveRoute[1] = UPY;
|
||||
saveRoute[0] = 0;
|
||||
while ((lastVal == (routeDestCalc + ROUTE_GRID_WIDTH)[0]) && (!routeDone)) {
|
||||
routeDestCalc += ROUTE_GRID_WIDTH; // keep checking right
|
||||
saveRoute[0] += WALK_JUMP;
|
||||
#ifdef ARDEBUG
|
||||
printf("down\n");
|
||||
#endif
|
||||
lastVal--;
|
||||
if (lastVal == 0) routeDone = true;
|
||||
}
|
||||
} else {
|
||||
error("AutoRoute:: Can't find way backwards through _routeGrid");
|
||||
}
|
||||
} while (!routeDone);
|
||||
#ifdef ARDEBUG
|
||||
getchar();
|
||||
#endif
|
||||
// the route is done. if there was an initial x/y movement tag it onto the start
|
||||
if (initX < 0) {
|
||||
saveRoute -= 2;
|
||||
saveRoute[1] = RIGHTY;
|
||||
saveRoute[0] = ((-initX) + 7) & 0xFFF8;
|
||||
} else if (initX > 0) {
|
||||
saveRoute -= 2;
|
||||
saveRoute[1] = LEFTY;
|
||||
saveRoute[0] = (initX + 7) & 0xFFF8;
|
||||
}
|
||||
// I wonder why initY isn't checked
|
||||
// saveRoute should now point to routeData
|
||||
if (routeData > saveRoute) error("Autoroute: Internal pointer error! routeData overflow.");
|
||||
*pSaveRoute = saveRoute;
|
||||
return 1;
|
||||
return foundRoute;
|
||||
}
|
||||
|
||||
uint16 *SkyAutoRoute::makeRouteData(uint8 startX, uint8 startY, uint8 destX, uint8 destY) {
|
||||
|
||||
memset(_routeBuf, 0, ROUTE_SPACE);
|
||||
|
||||
uint16 *routePos = _routeGrid + (destY + 1) * ROUTE_GRID_WIDTH + destX + 1;
|
||||
uint16 *dataTrg = _routeBuf + (ROUTE_SPACE >> 1) - 2;
|
||||
|
||||
uint16 lastVal = (*routePos) - 1;
|
||||
while (lastVal) { // lastVal == 0 means route is done.
|
||||
dataTrg -= 2;
|
||||
|
||||
int16 walkDirection = 0;
|
||||
for (uint8 cnt = 0; cnt < 4; cnt++)
|
||||
if (lastVal == *(routePos + _routeDirections[cnt])) {
|
||||
*(dataTrg + 1) = _logicCommands[cnt];
|
||||
walkDirection = _routeDirections[cnt];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!walkDirection)
|
||||
error("makeRouteData:: can't find way through walkGrid (pos %d)", lastVal);
|
||||
while (lastVal && (lastVal == *(routePos + walkDirection))) {
|
||||
*dataTrg += WALK_JUMP;
|
||||
lastVal--;
|
||||
routePos += walkDirection;
|
||||
}
|
||||
}
|
||||
return dataTrg;
|
||||
}
|
||||
|
||||
uint16 *SkyAutoRoute::checkInitMove(uint16 *data, int16 initStaX) {
|
||||
if (initStaX < 0) {
|
||||
data -= 2;
|
||||
*(data + 1) = RIGHTY;
|
||||
*data = ((-initStaX) + 7) & 0xFFF8;
|
||||
} else if (initStaX > 0) {
|
||||
data -= 2;
|
||||
*(data + 1) = LEFTY;
|
||||
*data = (initStaX + 7) & 0xFFF8;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint16 SkyAutoRoute::autoRoute(Compact *cpt) {
|
||||
|
||||
uint8 cptScreen = (uint8)cpt->screen;
|
||||
uint8 cptWidth = (uint8)SkyCompact::getMegaSet(cpt, cpt->extCompact->megaSet)->gridWidth;
|
||||
initWalkGrid(cptScreen, cptWidth);
|
||||
|
||||
uint8 startX, startY, destX, destY;
|
||||
int16 initStaX, initStaY, initDestX, initDestY;
|
||||
|
||||
clipCoordX(cpt->xcood, startX, initStaX);
|
||||
clipCoordY(cpt->ycood, startY, initStaY);
|
||||
clipCoordX(cpt->extCompact->arTargetX, destX, initDestX);
|
||||
clipCoordY(cpt->extCompact->arTargetY, destY, initDestY);
|
||||
|
||||
((uint16*)cpt->extCompact->animScratch)[0] = 0;
|
||||
if ((startX == destX) && (startY == destY))
|
||||
return 1;
|
||||
|
||||
if (_routeGrid[(destY + 1) * ROUTE_GRID_WIDTH + destX + 1])
|
||||
return 2; // AR destination is an unaccessible block
|
||||
|
||||
if (!calcWalkGrid(startX, startY, destX, destY))
|
||||
return 2; // can't find route to block
|
||||
|
||||
uint16 *routeData = makeRouteData(startX, startY, destX, destY);
|
||||
// the route is done.
|
||||
// if there was an initial x movement (due to clipping) tag it onto the start
|
||||
routeData = checkInitMove(routeData, initStaX);
|
||||
|
||||
uint8 cnt = 0;
|
||||
do {
|
||||
((uint16*)cpt->extCompact->animScratch)[cnt] = routeData[cnt];
|
||||
((uint16*)cpt->extCompact->animScratch)[cnt + 1] = routeData[cnt + 1];
|
||||
cnt += 2;
|
||||
} while (routeData[cnt - 2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,20 @@ class SkyAutoRoute {
|
||||
public:
|
||||
SkyAutoRoute(SkyGrid *pGrid);
|
||||
~SkyAutoRoute(void);
|
||||
uint16 autoRoute(Compact *cpt, uint16 **pSaveRoute);
|
||||
uint16 autoRoute(Compact *cpt);
|
||||
private:
|
||||
uint16 checkBlock(uint16 *blockPos);
|
||||
void clipCoordX(uint16 x, uint8 &blkX, int16 &initX);
|
||||
void clipCoordY(uint16 y, uint8 &blkY, int16 &initY);
|
||||
void initWalkGrid(uint8 screen, uint8 width);
|
||||
bool calcWalkGrid(uint8 startX, uint8 startY, uint8 destX, uint8 destY);
|
||||
uint16 *makeRouteData(uint8 startX, uint8 startY, uint8 destX, uint8 destY);
|
||||
uint16 *checkInitMove(uint16 *data, int16 initStaX);
|
||||
SkyGrid *_grid;
|
||||
uint16 *_routeGrid;
|
||||
uint16 *_routeBuf;
|
||||
static const int16 _routeDirections[4];
|
||||
static const uint16 _logicCommands[4];
|
||||
};
|
||||
|
||||
#endif // AUTOROUTE_H
|
||||
|
@ -144,20 +144,13 @@ void SkyLogic::logicScript() {
|
||||
}
|
||||
|
||||
void SkyLogic::autoRoute() {
|
||||
uint16 *route = 0;
|
||||
uint16 ret = _skyAutoRoute->autoRoute(_compact, &route);
|
||||
|
||||
_compact->downFlag = _skyAutoRoute->autoRoute(_compact);
|
||||
if (!_compact->downFlag) // route ok
|
||||
_compact->grafixProg = (uint16*)_compact->extCompact->animScratch;
|
||||
|
||||
_compact->logic = L_SCRIPT; // continue the script
|
||||
|
||||
if (ret != 1) // route failed
|
||||
_compact->downFlag = 1; // return fail to script
|
||||
else if (!route) // zero route
|
||||
_compact->downFlag = 2; // return fail to script
|
||||
else {
|
||||
_compact->grafixProg = route; // put graphic prog in
|
||||
_compact->downFlag = 0; // route ok
|
||||
}
|
||||
|
||||
logicScript();
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user