#include "ga_chaser.hpp" #include #include "ga_trig.hpp" #include "ga_arena.hpp" #include "ga_player.hpp" #include "ga_vector3D.hpp" #ifdef _AS_VERSION_PC #include "pc_matrix.hpp" #else #include extern void ResetMatrix(short m[3][3]); extern short VAB; #endif extern int gameOver; // just temporary //AsChaserManager *chaserManager; AsChaserManager::AsChaserManager() { // chaserManager = this; // temporary, till a better way is sorted numberOfChasers = 0; currentChaser = 0; for (int i = 0; i < AS_MAX_CHASERS; i++) chasers[i] = new AsChaser(); maxChasers[0] = 3; maxChasers[1] = AS_MAX_CHASERS; } AsChaserManager::~AsChaserManager() { for (int i = 0; i < AS_MAX_CHASERS; i++) delete chasers[i]; } void AsChaserManager::Reset() { for (int i = 0; i < AS_MAX_CHASERS; i++) chasers[i]->Reset(); numberOfChasers = 0; chaserCurrentTime = 0; numberToRelease = 0; } int AsChaserManager::Count() { return(numberOfChasers); } AsChaser *AsChaserManager::GetCurrentChaser() { return(chasers[currentChaser]); } AsChaser *AsChaserManager::GetChaser(int i) { return(chasers[i]); } int AsChaserManager::TestChaserMovement(int chaserNumber) { AsMapArrayElement *mapArray; AsMapLink link; int xDifference, yDifference, zDifference, absxDifference, abszDifference; int blockCurrent, blockReverse; int xClose, zClose; int currentBlockX,currentBlockY,currentBlockZ; // block of chaserNumber int directionBlockX,directionBlockY,directionBlockZ; // next block in current direction int reverseBlockX,reverseBlockY,reverseBlockZ; // next block in reverse direction int checkBlockX,checkBlockY,checkBlockZ; // set for use in standard equation int block; int otherX,otherY,otherZ; int baseX, baseZ; int direction, currentDirection, reverseDirection; int rotation, currentRotation, reverseRotation; int behindCurrent,behindReverse; behindCurrent = behindReverse = 0; blockCurrent = blockReverse = reverseDirection = 0; currentDirection = chasers[chaserNumber]->GetDirection(); reverseDirection = chasers[chaserNumber]->GetReverseDirection(); currentBlockY = chasers[chaserNumber]->yRoom; currentBlockX = chasers[chaserNumber]->xRoom; currentBlockZ = chasers[chaserNumber]->zRoom; directionBlockY = currentBlockY; directionBlockX = currentBlockX; directionBlockZ = currentBlockZ; mapArray = map->GetMapArray(directionBlockY,directionBlockX,directionBlockZ); if (mapArray->adjacentBlock[currentDirection] > 1) // link { link = map->links[mapArray->adjacentBlock[currentDirection]]; directionBlockY = link.y; directionBlockX = link.x; directionBlockZ = link.z; if (currentDirection != link.direction) currentRotation = map->GetRotation(currentDirection,link.direction); } else // normal adjacent block { switch(currentDirection) { case AS_MAP_UP: directionBlockX--; break; case AS_MAP_DOWN: directionBlockX++; break; case AS_MAP_LEFT: directionBlockZ--; break; case AS_MAP_RIGHT: directionBlockZ++; break; } } reverseBlockY = currentBlockY; reverseBlockX = currentBlockX; reverseBlockZ = currentBlockZ; if (mapArray->adjacentBlock[reverseDirection] > 1) // link { link = map->links[mapArray->adjacentBlock[reverseDirection]]; reverseBlockY = link.y; reverseBlockX = link.x; reverseBlockZ = link.z; if (reverseDirection != link.direction) reverseRotation = map->GetRotation(reverseDirection,link.direction); } else // normal adjacent block { switch(reverseDirection) { case AS_MAP_UP: reverseBlockX--; break; case AS_MAP_DOWN: reverseBlockX++; break; case AS_MAP_LEFT: reverseBlockZ--; break; case AS_MAP_RIGHT: reverseBlockZ++; break; } } for (int i = 0; i < numberOfChasers; i++) { if (i != chaserNumber) { block = 0; // first check to see if same or adjacent block if ((currentBlockX == chasers[i]->xRoom) && (currentBlockY == chasers[i]->yRoom) && (currentBlockZ == chasers[i]->zRoom)) block = 1; // same else { if ((directionBlockX == chasers[i]->xRoom) && (directionBlockY == chasers[i]->yRoom) && (directionBlockZ == chasers[i]->zRoom)) block = 2; // adjacent else { if ((reverseBlockX == chasers[i]->xRoom) && (reverseBlockY == chasers[i]->yRoom) && (reverseBlockZ == chasers[i]->zRoom)) block = 3; // reverse } } /* not accurate enough switch(block) { case 1: { if (!((player->xRoom == currentBlockX)&&(player->yRoom == currentBlockY)&&(player->zRoom == currentBlockZ))) blockCurrent = 1; break; } case 2: { if (!((player->xRoom == directionBlockX)&&(player->yRoom == directionBlockY)&&(player->zRoom == directionBlockZ))) blockCurrent = 1; break; } case 3: blockReverse = 1; break; } */ if ((player->xRoom == currentBlockX)&&(player->yRoom == currentBlockY)&&(player->zRoom == currentBlockZ)) continue; switch(block) { case 0: // not near, move to next chaser continue; case 1: // same { checkBlockX = currentBlockX; checkBlockY = currentBlockY; checkBlockZ = currentBlockZ; break; } case 2: // adjacent { checkBlockX = directionBlockX; checkBlockY = directionBlockY; checkBlockZ = directionBlockZ; break; } case 3: // reverse { checkBlockX = reverseBlockX; checkBlockY = reverseBlockY; checkBlockZ = reverseBlockZ; break; } } // now check the distance // first find the baseX and baseZ of the i'th chasers block baseX = 0; baseZ = 0; if (block == 1) // for same block, no need to check if 'behind' { switch(currentDirection) { case AS_MAP_UP: if (chasers[chaserNumber]->X < chasers[i]->X) behindCurrent = 1; break; case AS_MAP_DOWN: if (chasers[chaserNumber]->X > chasers[i]->X) behindCurrent = 1; break; case AS_MAP_LEFT: if (chasers[chaserNumber]->Z < chasers[i]->Z) behindCurrent = 1; break; case AS_MAP_RIGHT: if (chasers[chaserNumber]->Z > chasers[i]->Z) behindCurrent = 1; break; } switch(reverseDirection) { case AS_MAP_UP: if (chasers[chaserNumber]->X < chasers[i]->X) behindReverse = 1; break; case AS_MAP_DOWN: if (chasers[chaserNumber]->X > chasers[i]->X) behindReverse = 1; break; case AS_MAP_LEFT: if (chasers[chaserNumber]->Z < chasers[i]->Z) behindReverse = 1; break; case AS_MAP_RIGHT: if (chasers[chaserNumber]->Z > chasers[i]->Z) behindReverse = 1; break; } } else // current and reverse, check other direction { if (block == 2) { direction = currentDirection; rotation = currentRotation; } else { direction = reverseDirection; rotation = reverseRotation; } switch(direction) // this could be optimised but it would be difficult to follow { case AS_MAP_UP: { switch(rotation) { case 0: baseX = -AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_90: baseZ = AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_180: baseX = AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_270: baseZ = -AS_MAP_ROOM_LENGTH; break; } break; } case AS_MAP_DOWN: { switch(rotation) { case 0: baseX = AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_90: baseZ = -AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_180: baseX = -AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_270: baseZ = AS_MAP_ROOM_LENGTH; break; } break; } case AS_MAP_LEFT: { switch(rotation) { case 0: baseZ = -AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_90: baseX = -AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_180: baseZ = AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_270: baseX = AS_MAP_ROOM_LENGTH; break; } break; } case AS_MAP_RIGHT: { switch(rotation) { case 0: baseZ = AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_90: baseX = AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_180: baseZ = -AS_MAP_ROOM_LENGTH; break; case AS_DEGREES_270: baseX = -AS_MAP_ROOM_LENGTH; break; } break; } } } // else block // calculate difference xDifference = chasers[chaserNumber]->X - (chasers[i]->X + baseX); zDifference = chasers[chaserNumber]->Z - (chasers[i]->Z + baseZ); // 1440000 = precalculated 1200 * 1200 if (((xDifference * xDifference) + (zDifference * zDifference)) < 1440000) { if (block <= 2) // current or direction { if (!behindCurrent) blockCurrent = 1; } else { if (!behindReverse) blockReverse = 1; // collision doesn't necessarily result in action } } /* // if same room, then check distance between values if ((chasers[chaserNumber]->xRoom == chasers[i]->xRoom) && (chasers[chaserNumber]->yRoom == chasers[i]->yRoom) && (chasers[chaserNumber]->zRoom == chasers[i]->zRoom)) { if ((abs(chasers[chaserNumber]->X - chasers[i]->X) < 1200) && (abs(chasers[chaserNumber]->Y - chasers[i]->Y) < 1200) && (abs(chasers[chaserNumber]->Z - chasers[i]->Z) < 1200)) { blockCurrent = 1; blockReverse = 1; } } if ((directionBlockX == chasers[i]->xRoom) && (directionBlockY == chasers[i]->yRoom) && (directionBlockZ == chasers[i]->zRoom)) { for (int r = 0; r < AS_MAX_REPLICATE; r++) { if (map->visualMap[r][directionBlockX][directionBlockY][directionBlockZ]) { otherX = chasers[i]->X + map->visualX[r][directionBlockX][directionBlockY][directionBlockZ]; otherY = chasers[i]->Y + map->visualY[r][directionBlockX][directionBlockY][directionBlockZ]; otherZ = chasers[i]->Z + map->visualZ[r][directionBlockX][directionBlockY][directionBlockZ]; if ((abs(chasers[chaserNumber]->X - otherX) < 1200) && (abs(chasers[chaserNumber]->Y - otherY) < 1200) && (abs(chasers[chaserNumber]->Z - otherZ) < 1200)) blockCurrent = 1; } } } if ((reverseBlockX == chasers[i]->xRoom) && (reverseBlockY == chasers[i]->yRoom) && (reverseBlockZ == chasers[i]->zRoom)) { for (int r = 0; r < AS_MAX_REPLICATE; r++) { if (map->visualMap[r][reverseBlockX][reverseBlockY][reverseBlockZ]) { otherX = chasers[i]->X + map->visualX[r][reverseBlockX][reverseBlockY][reverseBlockZ]; otherY = chasers[i]->Y + map->visualY[r][reverseBlockX][reverseBlockY][reverseBlockZ]; otherZ = chasers[i]->Z + map->visualZ[r][reverseBlockX][reverseBlockY][reverseBlockZ]; if ((abs(chasers[chaserNumber]->X - otherX) < 1200) && (abs(chasers[chaserNumber]->Y - otherY) < 1200) && (abs(chasers[chaserNumber]->Z - otherZ) < 1200)) blockReverse = 1; } } }*/ } // if !i } // for i return(blockCurrent | (blockReverse << 1) | (reverseDirection << 2)); /* for (int i = 0; i < numberOfChasers; i++) { if (i != chaserNumber) { yDifference = chasers[i]->GetY() - chasers[chaserNumber]->GetY(); if ((yDifference < 1500.0) && (yDifference > -1500.0)) { xDifference = chasers[i]->X - chasers[chaserNumber]->X; zDifference = chasers[i]->Z - chasers[chaserNumber]->Z; //absxDifference = abs(xDifference); //abszDifference = abs(zDifference); xClose = ((xDifference >= -1000) && (xDifference <= 1000)); zClose = ((zDifference >= -1000) && (zDifference <= 1000)); switch(chasers[chaserNumber]->GetDirection()) { case AS_CHASER_DIRECTION_UP: if ((xDifference >= -1000) && (xDifference <= 0) && zClose) blockCurrent = 1; break; case AS_CHASER_DIRECTION_DOWN:if ((xDifference <= 1000) && (xDifference >= 0) && zClose) blockCurrent = 1; break; case AS_CHASER_DIRECTION_LEFT: if ((zDifference >= -1000) && (zDifference <= 0) && xClose) blockCurrent = 1; break; case AS_CHASER_DIRECTION_RIGHT:if ((zDifference <= 1000) && (zDifference >= 0) && xClose) blockCurrent = 1; break; } reverseDirection = chasers[chaserNumber]->GetReverseDirection(); switch(reverseDirection) { case AS_CHASER_DIRECTION_UP: if ((xDifference >= -1000) && (xDifference <= 0) && zClose) blockCurrent = 1; break; case AS_CHASER_DIRECTION_DOWN:if ((xDifference <= 1000) && (xDifference >= 0) && zClose) blockCurrent = 1; break; case AS_CHASER_DIRECTION_LEFT: if ((zDifference >= -1000) && (zDifference <= 0) && xClose) blockCurrent = 1; break; case AS_CHASER_DIRECTION_RIGHT:if ((zDifference <= 1000) && (zDifference >= 0) && xClose) blockCurrent = 1; break; } } } } return(blockCurrent | (blockReverse << 1) | (reverseDirection << 2)); */ } int AsChaserManager::CheckPosition(int chaserNumber) { int chaserScenarios = TestChaserMovement(chaserNumber); if ((chaserScenarios & 0x01) && (chaserScenarios & 0x02)) // 0x01 | 0x02, both current and reverse blocked so stop return(1); if (chaserScenarios & 0x01) // 0x01, only current blocked, so set direction to reverse chasers[chaserNumber]->SetDirection(chaserScenarios >> 2); return(0); } void AsChaserManager::Update(int mapNumber) { int level, row, column, oldLevel, oldRow, oldColumn; int baseX, baseY, baseZ; int chaserSubX, chaserSubY, chaserSubZ; AsMapArrayElement *mapArray; int limit,direction,newDirection; int rotation = 0; AsChaser *current; int around; int startPoint; AsMapLink link; Vector vector; #ifdef _AS_VERSION_PC Matrix3D rotationMatrix; #else MATRIX rotationMatrix; SVECTOR rotationVector; SVECTOR inputVector; VECTOR outputVector; #endif chaserCurrentTime++; // if (numberToRelease < 0) numberToRelease = 0; if ((chaserCurrentTime % 250) == 0) // 5 secs // || (numberToRelease)) { if (numberOfChasers < maxChasers[mapNumber]) { int chaserTest = TestChaserMovement(numberOfChasers); if (!(chaserTest & 0x01)) // current direction blocked { startPoint = -1; numberToRelease--; //if ((chaserCurrentTime % 500) == 0) // every 20 secs switch(mapNumber) { case 0: { switch (chaserCurrentTime % 500) { case 250:if (!map->visualMap[0][0][2][0])startPoint = 0; break; case 0:if (!map->visualMap[0][0][8][2])startPoint = 1; break; } if (startPoint >= 0) { switch (startPoint) { case 0: { chasers[numberOfChasers]->xRoom = 2; chasers[numberOfChasers]->yRoom = 0; chasers[numberOfChasers]->zRoom = 0; break; } case 1: { chasers[numberOfChasers]->xRoom = 8; chasers[numberOfChasers]->yRoom = 0; chasers[numberOfChasers]->zRoom = 2; break; } } // switch startpoint numberOfChasers++; } // if startpoint >= 0 break; } case 1: { switch (chaserCurrentTime % 1000) { case 500:if (!map->visualMap[0][3][5][8])startPoint = 0; break; case 250:if (!map->visualMap[0][0][4][0])startPoint = 1; break; //case 0:if (!map->visualMap[0][3][2][2])startPoint = 2; break; case 0:if (!map->visualMap[0][2][0][7])startPoint = 2; break; case 750:if (!map->visualMap[0][1][5][4])startPoint = 3; break; } if (startPoint >= 0) { switch (startPoint) { case 0: { chasers[numberOfChasers]->xRoom = 5; chasers[numberOfChasers]->yRoom = 3; chasers[numberOfChasers]->zRoom = 8; break; } case 1: { chasers[numberOfChasers]->xRoom = 4; chasers[numberOfChasers]->yRoom = 0; chasers[numberOfChasers]->zRoom = 0; break; } case 2: { chasers[numberOfChasers]->xRoom = 0;//2; chasers[numberOfChasers]->yRoom = 2;//3; chasers[numberOfChasers]->zRoom = 7;//2; break; } case 3: { chasers[numberOfChasers]->xRoom = 5; chasers[numberOfChasers]->yRoom = 1; chasers[numberOfChasers]->zRoom = 4; break; } } // switch startpoint numberOfChasers++; } // if startpoint >= 0 break; } }// switch mapNumber } // current direction blocked else { numberToRelease++; // not utilised yet - see if statement above } } // if under max } // 10 secs // for (int i = 0; i < numberOfChasers; i++) { rotation = 0; currentChaser = i; current = GetChaser(i); if (!current->Delay()) { // use the map element from the last position level = current->yRoom;//Y / AS_MAP_ROOM_LENGTH; column = current->zRoom;//Z / AS_MAP_ROOM_LENGTH; row = current->xRoom;//X / AS_MAP_ROOM_LENGTH; mapArray = map->GetMapArray(level,row,column); chaserSubX = current->X; chaserSubY = current->Y;//AS_CHASER_LEGS; chaserSubZ = current->Z; limit = CheckPosition(i); if (limit) continue; // chaser cannot move if ((chaserSubX == 1000) && (chaserSubZ == 1000)) // time to check direction { direction = FindPlayer(current); if (direction < 0) // player not found so patrol { direction = directionGenerator.GetDirection(mapArray,current->GetDirection()); } current->SetDirection(direction); } current->UpdatePosition(); chaserSubX = current->X;// - baseX; chaserSubZ = current->Z;// - baseZ; int direction = -1; if (chaserSubX < 0) direction = AS_MAP_UP; if (chaserSubX >= AS_MAP_ROOM_LENGTH) direction = AS_MAP_DOWN; if (chaserSubZ < 0) direction = AS_MAP_LEFT; if (chaserSubZ >= AS_MAP_ROOM_LENGTH) direction = AS_MAP_RIGHT; if (direction >= 0) { if (mapArray->adjacentBlock[direction] > 1) // link { link = map->links[mapArray->adjacentBlock[direction]]; level = link.y; row = link.x; column = link.z; if (direction != link.direction) { rotation = map->GetRotation(direction,link.direction); newDirection = map->ConvertDirection(direction,rotation); current->SetDirection(newDirection); } } else // normal adjacent block { switch(direction) { case AS_MAP_UP: row--; break; case AS_MAP_DOWN: row++; break; case AS_MAP_LEFT: column--; break; case AS_MAP_RIGHT: column++; break; } } } if (chaserSubX >= AS_MAP_ROOM_LENGTH) chaserSubX -= AS_MAP_ROOM_LENGTH; if (chaserSubZ >= AS_MAP_ROOM_LENGTH) chaserSubZ -= AS_MAP_ROOM_LENGTH; if (chaserSubX < 0) chaserSubX += AS_MAP_ROOM_LENGTH; if (chaserSubZ < 0) chaserSubZ += AS_MAP_ROOM_LENGTH; mapArray = map->GetMapArray(level,row,column); chaserSubY = 0; switch (mapArray->stairInfo) { case AS_MAP_STAIRS_LEFTTORIGHT: chaserSubY = chaserSubZ + AS_CHASER_LEGS; break; case AS_MAP_STAIRS_RIGHTTOLEFT: chaserSubY = (AS_MAP_ROOM_LENGTH - chaserSubZ) + AS_CHASER_LEGS; break; case AS_MAP_STAIRS_UPTODOWN: chaserSubY = chaserSubX + AS_CHASER_LEGS; break; case AS_MAP_STAIRS_DOWNTOUP: chaserSubY = (AS_MAP_ROOM_LENGTH - chaserSubX) + AS_CHASER_LEGS; break; default: if (chaserSubY < AS_CHASER_LEGS) chaserSubY = AS_CHASER_LEGS; } if (rotation) { #ifdef _AS_VERSION_PC rotationMatrix.Initialize(); rotationMatrix.Rotate(0,-rotation,0); vector.X = chaserSubX - 1000; vector.Y = chaserSubY - 1000; vector.Z = chaserSubZ - 1000; rotationMatrix.Transform(vector); chaserSubX = vector.Tx + 1000 + 0.5; chaserSubY = vector.Ty + 1000 + 0.5; chaserSubZ = vector.Tz + 1000 + 0.5; #else ResetMatrix(rotationMatrix.m); rotationVector.vx = 0; rotationVector.vy = -rotation; rotationVector.vz = 0; RotMatrix(&rotationVector,&rotationMatrix); inputVector.vx = chaserSubX - 1000; inputVector.vy = chaserSubY - 1000; inputVector.vz = chaserSubZ - 1000; ApplyMatrix(&rotationMatrix,&inputVector,&outputVector); chaserSubX = outputVector.vx + 1000;// + 0.5; chaserSubY = outputVector.vy + 1000;// + 0.5; chaserSubZ = outputVector.vz + 1000;// + 0.5; #endif //current->aroundY = (current->aroundY + rotation) % AS_DEGREES_360; } current->SetPosition(chaserSubX, chaserSubY, chaserSubZ); current->xRoom = row; current->yRoom = level; current->zRoom = column; }// if not delay #ifdef _AS_VERSION_PC around = 64; #else around = 16; #endif current->aroundX += around; current->aroundY += around; current->aroundZ += around; } } void AsChaserManager::SetFeatures(AsArenaBuilder *_map,AsPlayer *_player) { map = _map; player = _player; } void AsChaserManager::GroundSearch2(int &distanceFound, int distanceTraversed, int level,int row,int column, int direction, int length, int type,int oldDirection,int rotation,int depth)//, AsPathElement *directions) { int sx, sy, sz; int count, adjacentBlock,currentBlockStairStatus,lastBlockStairStatus; int newDistance; int rowChange,colChange; AsMapLink link; int replicate; int newDirection; AsMapArrayElement *mapArray; int newRotation = 0; int subSearch; distanceFound = 999; // this value is only passed up, not down depth++; sy = level; sx = row; sz = column; count = length; mapArray = map->GetMapArray(sy,sx,sz); adjacentBlock = mapArray->adjacentBlock[direction]; lastBlockStairStatus = mapArray->stairInfo; while(adjacentBlock && count) { // Obtain adjacentBlock - either a straightforward adjacent block or a link if (adjacentBlock == 1) // values > 1 indicate a link { switch(direction) { case AS_MAP_UP: sx--; break; case AS_MAP_DOWN: sx++; break; case AS_MAP_LEFT: sz--; break; case AS_MAP_RIGHT: sz++; break; } } else // a link { link = map->links[adjacentBlock]; sx = link.x; sy = link.y; sz = link.z; newDirection = link.direction; if (newDirection != direction) { newRotation = map->GetRotation(direction, newDirection); oldDirection = map->ConvertDirection(oldDirection,newRotation); rotation = (rotation + newRotation) % AS_DEGREES_360; direction = newDirection; } } // identify chaser /* for (int i = 0; i < chaserManager->numberOfChasers; i++) { if ((sx == chasers[i]->xRoom) && (sy == chasers[i]->yRoom) && (sz == chasers[i]->zRoom)) return; } */ // identify player - store distance based on distanceTraversed if ((sx == player->xRoom) && (sy == player->yRoom) && (sz == player->zRoom)) { newDistance = distanceTraversed; if (newDistance < distanceFound) { distanceFound = newDistance; //directions.direction[depth] = direction; // this direction already represents rotated direction //directions.xBlock = row; //directions.yBlock = level; //directions.zBlock = column; } } if (chasers[currentChaser]->chaseMode) subSearch = AS_MAX_SEARCH; else subSearch = 1; // recurse the search switch(type) { case AS_MAP_SEARCH_MAIN_LOOP: { if (count == length) // i.e. first adjacent block (haven't decreased count yet) { switch(direction) { case AS_MAP_LEFT: case AS_MAP_RIGHT: { GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_UP,AS_MAX_SEARCH,AS_MAP_SEARCH_FIRST_ADJACENT,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_DOWN,AS_MAX_SEARCH,AS_MAP_SEARCH_FIRST_ADJACENT,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; break; } case AS_MAP_UP: case AS_MAP_DOWN: { GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_LEFT,AS_MAX_SEARCH,AS_MAP_SEARCH_FIRST_ADJACENT,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_RIGHT,AS_MAX_SEARCH,AS_MAP_SEARCH_FIRST_ADJACENT,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; break; } } } else // Don't do the adjacent search, just one block off in each direction { switch(direction) { case AS_MAP_LEFT: case AS_MAP_RIGHT: { GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_UP,subSearch,AS_MAP_SEARCH_NO_RECURSION,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_DOWN,subSearch,AS_MAP_SEARCH_NO_RECURSION,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; break; } case AS_MAP_UP: case AS_MAP_DOWN: { GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_LEFT,subSearch,AS_MAP_SEARCH_NO_RECURSION,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,AS_MAP_RIGHT,subSearch,AS_MAP_SEARCH_NO_RECURSION,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; break; } } } break; } case AS_MAP_SEARCH_FIRST_ADJACENT: { // oldDirection is the original direction of search, used to avoid going back on oneself in this adjacent search GroundSearch2(newDistance,distanceTraversed,sy,sx,sz,oldDirection,1,AS_MAP_SEARCH_NO_RECURSION,direction,rotation,depth); if (newDistance < distanceFound) distanceFound = newDistance; break; } case AS_MAP_SEARCH_NO_RECURSION: break; // do nothing } // end of switch(type) // tidy loop count--; distanceTraversed++; mapArray = map->GetMapArray(sy,sx,sz); adjacentBlock = mapArray->adjacentBlock[direction]; } } /* int AsChaserManager::GroundSearch(int level,int row,int column, int searchDirection, int length, int recurse, int depth) { int sx, sz; int count, adjacentLevel, currentLevel,lastLevel; int directionFound; depth--; switch(searchDirection) { case 0: // horiz { // left sz = column; currentLevel = level; count = length; adjacentLevel = map->GetMapArray(level,row,sz)->adjacentLevelNumber[AS_MAP_LEFT]; while(adjacentLevel && count) { lastLevel = currentLevel; currentLevel = adjacentLevel - AS_MAP_LEVEL_OFFSET; if (currentLevel == lastLevel) sz--; if ((player->xRoom == row) && (player->yRoom == currentLevel) && (player->zRoom == sz)) return(AS_CHASER_DIRECTION_LEFT); // player found in this direction if (recurse && depth) { if (sz == (column - 1)) directionFound = GroundSearch(currentLevel,row,sz,1,AS_MAX_SEARCH,1,depth); else directionFound = GroundSearch(currentLevel,row,sz,1,1,0,depth); if (directionFound >= 0) // in chase mode, actual direction irrelevant, so return first search direction return(AS_CHASER_DIRECTION_LEFT); } count--; adjacentLevel = map->GetMapArray(currentLevel,row,sz)->adjacentLevelNumber[AS_MAP_LEFT]; } // right sz = column; currentLevel = level; count = length; adjacentLevel = map->GetMapArray(level,row,sz)->adjacentLevelNumber[AS_MAP_RIGHT]; while(adjacentLevel && count) { lastLevel = currentLevel; currentLevel = adjacentLevel - AS_MAP_LEVEL_OFFSET; if (currentLevel == lastLevel) sz++; if ((player->xRoom == row) && (player->yRoom == currentLevel) && (player->zRoom == sz)) return(AS_CHASER_DIRECTION_RIGHT); // player found in this direction if (recurse && depth) { if (sz == (column + 1)) directionFound = GroundSearch(currentLevel,row,sz,1,AS_MAX_SEARCH,1,depth); else directionFound = GroundSearch(currentLevel,row,sz,1,1,0,depth); if (directionFound >= 0) // in chase mode, actual direction irrelevant, so return first search direction return(AS_CHASER_DIRECTION_RIGHT); } count--; adjacentLevel = map->GetMapArray(currentLevel,row,sz)->adjacentLevelNumber[AS_MAP_RIGHT]; } break; } case 1: // vert { // up sx = row; currentLevel = level; count = length; adjacentLevel = map->GetMapArray(level,sx,column)->adjacentLevelNumber[AS_MAP_UP]; while(adjacentLevel && count) { lastLevel = currentLevel; currentLevel = adjacentLevel - AS_MAP_LEVEL_OFFSET; if (currentLevel == lastLevel) sx--; if ((player->xRoom == sx) && (player->yRoom == currentLevel) && (player->zRoom == column)) return(AS_CHASER_DIRECTION_UP); // player found in this direction if (recurse && depth) { if (sx == (row - 1)) directionFound = GroundSearch(currentLevel,sx,column,0,AS_MAX_SEARCH,1,depth); else directionFound = GroundSearch(currentLevel,sx,column,0,1,0,depth); if (directionFound >= 0) // in chase mode, actual direction irrelevant, so return first search direction return(AS_CHASER_DIRECTION_UP); } count--; adjacentLevel = map->GetMapArray(currentLevel,sx,column)->adjacentLevelNumber[AS_MAP_UP]; } // down sx = row; currentLevel = level; count = length; adjacentLevel = map->GetMapArray(level,sx,column)->adjacentLevelNumber[AS_MAP_DOWN]; while(adjacentLevel && count) { lastLevel = currentLevel; currentLevel = adjacentLevel - AS_MAP_LEVEL_OFFSET; if (currentLevel == lastLevel) sx++; if ((player->xRoom == sx) && (player->yRoom == currentLevel) && (player->zRoom == column)) return(AS_CHASER_DIRECTION_DOWN); // player found in this direction if (recurse && depth) { if (sx == (row + 1)) directionFound = GroundSearch(currentLevel,sx,column,0,AS_MAX_SEARCH,1,depth); else directionFound = GroundSearch(currentLevel,sx,column,0,1,0,depth); if (directionFound >= 0) // in chase mode, actual direction irrelevant, so return first search direction return(AS_CHASER_DIRECTION_DOWN); } count--; adjacentLevel = map->GetMapArray(currentLevel,sx,column)->adjacentLevelNumber[AS_MAP_DOWN]; } break; } } return(-1); } */ int AsChaserManager::FindPlayer(AsChaser *chaser) { int level, row, column; int direction = -1; int distance = 998; int distanceFound = 1000; if (gameOver) return(-1); row = chaser->xRoom;//(int)(chaser->X / AS_MAP_ROOM_LENGTH); level = chaser->yRoom;//(int)(chaser->Y / AS_MAP_ROOM_LENGTH); column = chaser->zRoom;//(int)(chaser->Z / AS_MAP_ROOM_LENGTH); GroundSearch2(distanceFound,0,level,row,column,AS_MAP_UP,AS_MAX_SEARCH,AS_MAP_SEARCH_MAIN_LOOP,AS_MAP_UP,0,-1); if (distanceFound < distance) { distance = distanceFound; direction = AS_MAP_UP; } GroundSearch2(distanceFound,0,level,row,column,AS_MAP_DOWN,AS_MAX_SEARCH,AS_MAP_SEARCH_MAIN_LOOP,AS_MAP_DOWN,0,-1); if (distanceFound < distance) { distance = distanceFound; direction = AS_MAP_DOWN; } GroundSearch2(distanceFound,0,level,row,column,AS_MAP_LEFT,AS_MAX_SEARCH,AS_MAP_SEARCH_MAIN_LOOP,AS_MAP_LEFT,0,-1); if (distanceFound < distance) { distance = distanceFound; direction = AS_MAP_LEFT; } GroundSearch2(distanceFound,0,level,row,column,AS_MAP_RIGHT,AS_MAX_SEARCH,AS_MAP_SEARCH_MAIN_LOOP,AS_MAP_RIGHT,0,-1); if (distanceFound < distance) { direction = AS_MAP_RIGHT; } if (direction >= 0) { #ifndef _AS_VERSION_PC //if (!chaser->chaseMode) // SsUtKeyOn(VAB, 1, 0,28, 0, 100, 100); #endif chaser->chaseMode = 1; } else chaser->chaseMode = 0; return(direction); } AsDirectionGenerator::AsDirectionGenerator() { } int AsDirectionGenerator::GetRandomRightAngle(int currentDirection) { int direction; int randomFactor = rand() % 2; switch(currentDirection) { case AS_CHASER_DIRECTION_UP: case AS_CHASER_DIRECTION_DOWN: direction = AS_CHASER_DIRECTION_LEFT + randomFactor; break; case AS_CHASER_DIRECTION_LEFT: case AS_CHASER_DIRECTION_RIGHT: direction = AS_CHASER_DIRECTION_UP + randomFactor; break; } return(direction); } // This assumes that there is one available right angle, there is no error code int AsDirectionGenerator::GetAvailableRightAngle(AsMapArrayElement *mapArray,int currentDirection) { int direction; switch(currentDirection) { case AS_CHASER_DIRECTION_UP: case AS_CHASER_DIRECTION_DOWN: { if (mapArray->adjacentBlock[AS_MAP_LEFT]) return(AS_CHASER_DIRECTION_LEFT); else return(AS_CHASER_DIRECTION_RIGHT); } case AS_CHASER_DIRECTION_LEFT: case AS_CHASER_DIRECTION_RIGHT: { if (mapArray->adjacentBlock[AS_MAP_UP]) return(AS_CHASER_DIRECTION_UP); else return(AS_CHASER_DIRECTION_DOWN); } } } int AsDirectionGenerator::IsWayAheadClear(AsMapArrayElement *mapArray,int currentDirection) { switch(currentDirection) { case AS_CHASER_DIRECTION_UP: if (mapArray->adjacentBlock[AS_MAP_UP]) return(1); else return(0); case AS_CHASER_DIRECTION_DOWN: if (mapArray->adjacentBlock[AS_MAP_DOWN]) return(1); else return(0); case AS_CHASER_DIRECTION_LEFT: if (mapArray->adjacentBlock[AS_MAP_LEFT]) return(1); else return(0); case AS_CHASER_DIRECTION_RIGHT:if (mapArray->adjacentBlock[AS_MAP_RIGHT]) return(1); else return(0); } } int AsDirectionGenerator::GetDirection(AsMapArrayElement *mapArray,int currentDirection) { int direction; // Get number of sides of room int numberOfSides = 0; for (int i = 0; i < 4; i++) if (!mapArray->adjacentBlock[i]) numberOfSides++; switch(numberOfSides) { case 0: // change direction with 20% chance { if ((rand() % 5) < 4) return(currentDirection); // Now go at right angles direction = GetRandomRightAngle(currentDirection); break; } case 1: // If way ahead is clear, then change with 20% chance to available right angle, else pick right angle at random { if (IsWayAheadClear(mapArray,currentDirection)) { if ((rand() % 5) < 3) return(currentDirection); // change direction with 20% chance direction = GetAvailableRightAngle(mapArray,currentDirection); } else { direction = GetRandomRightAngle(currentDirection); } break; } case 2: // if way ahead is clear then don't change, else chose available right angle { if (IsWayAheadClear(mapArray,currentDirection)) return(currentDirection); else { direction = GetAvailableRightAngle(mapArray,currentDirection); } break; } case 3: // one way out - they way it came { switch(currentDirection) { case AS_CHASER_DIRECTION_UP: direction = AS_CHASER_DIRECTION_DOWN; break; case AS_CHASER_DIRECTION_DOWN: direction = AS_CHASER_DIRECTION_UP; break; case AS_CHASER_DIRECTION_LEFT: direction = AS_CHASER_DIRECTION_RIGHT; break; case AS_CHASER_DIRECTION_RIGHT: direction = AS_CHASER_DIRECTION_LEFT; break; } break; } default: direction = -1; } return(direction); } AsChaser::AsChaser() { Reset(); } void AsChaser::Reset() { X = 1000; #ifdef _AS_VERSION_PC Y = 1000; Z = 1000.0; #else Y = -1000; Z = -1000.0; #endif Y = 1000; Z = 1000.0; xRoom = 0; yRoom = 0; zRoom = 0; oldX = X; oldY = Y; oldZ = Z; aroundX = 0;//AS_DEGREES_45; aroundY = 0;//AS_DEGREES_45; aroundZ = 0;//AS_DEGREES_45; chaseMode = 0; //currentDirection[0].direction = -1; //currentDirection[1].direction = -1; //currentDirection[2].direction = -1; SetDirection(AS_MAP_RIGHT);//rand() % 4);//();AS_MAP_RIGHT // It will be revaluated first time around anyway delay = 0; } int AsChaser::Delay() { int oldDelay = delay; if (delay) delay--; return(oldDelay); } int AsChaser::GetDirection() { //return(currentDirection[0].direction); return(currentDirection); } int AsChaser::GetReverseDirection() { return(reverseDirection); } /* int AsChaser::SetNextDirection() { currentDirection[0].direction = currentDirection[1].direction; currentDirection[1].direction = currentDirection[2].direction; currentDirection[2].direction = -1; return(currentDirection[0].direction); } */ void AsChaser::SetDirection(int direction) { //currentDirection[0].direction = direction; currentDirection = direction; switch(direction) { case AS_CHASER_DIRECTION_UP: directionX = -AS_CHASER_MOVE_FACTOR; directionZ = 0; reverseDirection = AS_CHASER_DIRECTION_DOWN; break; case AS_CHASER_DIRECTION_DOWN: directionX = AS_CHASER_MOVE_FACTOR; directionZ = 0; reverseDirection = AS_CHASER_DIRECTION_UP; break; case AS_CHASER_DIRECTION_LEFT: directionX = 0; directionZ = -AS_CHASER_MOVE_FACTOR; reverseDirection = AS_CHASER_DIRECTION_RIGHT; break; case AS_CHASER_DIRECTION_RIGHT: directionX = 0; directionZ = AS_CHASER_MOVE_FACTOR; reverseDirection = AS_CHASER_DIRECTION_LEFT; break; } } void AsChaser::UpdatePosition() { X += directionX; Z += directionZ; } void AsChaser::Move(unsigned int angle) { X += SIN(angle) * AS_CHASER_MOVE_FACTOR; Z += COS(angle) * AS_CHASER_MOVE_FACTOR; } void AsChaser::MoveForward() { Move(aroundY); } void AsChaser::MoveBackward() { unsigned int angle = aroundY + AS_DEGREES_180; Move(angle); } void AsChaser::MoveLeft() { unsigned int angle = aroundY - AS_DEGREES_90; Move(angle); } void AsChaser::MoveRight() { unsigned int angle = aroundY + AS_DEGREES_90; Move(angle); } void AsChaser::StoreOldPosition() { oldX = X; oldY = Y; oldZ = Z; } void AsChaser::SetPosition(int newX, int newY, int newZ) { X = newX; Y = newY; Z = newZ; } void AsChaser::TurnLeft() { aroundY = (aroundY - AS_CHASER_ROTATE_FACTOR) % AS_DEGREES_360; } void AsChaser::TurnRight() { aroundY = (aroundY + AS_CHASER_ROTATE_FACTOR) % AS_DEGREES_360; } void AsChaser::LookUp() { aroundX = (aroundX - AS_CHASER_ROTATE_FACTOR) % AS_DEGREES_360; } void AsChaser::LookDown() { aroundX = (aroundX + AS_CHASER_ROTATE_FACTOR) % AS_DEGREES_360; } void AsChaser::TwistLeft() { aroundZ = (aroundZ - AS_CHASER_ROTATE_FACTOR) % AS_DEGREES_360; } void AsChaser::TwistRight() { aroundZ = (aroundZ + AS_CHASER_ROTATE_FACTOR) % AS_DEGREES_360; }