#include "ga_bullet.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]); #endif //AsBulletManager *bulletManager; AsBulletManager::AsBulletManager() { //bulletManager = this; // temporary, till a better way is sorted for (int i = 0; i < AS_MAX_BULLETS; i++) bullets[i] = new AsBullet(); } AsBulletManager::~AsBulletManager() { for (int i = 0; i < AS_MAX_BULLETS; i++) delete bullets[i]; } void AsBulletManager::Reset() { for (int i = 0; i < AS_MAX_BULLETS; i++) bullets[i]->Reset(); } AsBullet *AsBulletManager::GetBullet(int i) { return(bullets[i]); } void AsBulletManager::Update() { int level, row, column, oldLevel, oldRow, oldColumn; int baseX, baseY, baseZ; int bulletsSubX, bulletsSubY, bulletsSubZ; AsMapArrayElement *mapArray; int limit,direction,newDirection; int currentBlockStairStatus,lastBlockStairStatus; int lengthMinusNose = AS_MAP_ROOM_LENGTH - AS_BULLET_NOSE; int inactive; int movementMask; int rotation; AsMapLink link; AsBullet *bullet; Vector vector; #ifdef _AS_VERSION_PC Matrix3D rotationMatrix; #else MATRIX rotationMatrix; SVECTOR rotationVector; SVECTOR inputVector; VECTOR outputVector; #endif for (int i = 0; i < AS_MAX_BULLETS; i++) { // if ((i % 5) == 0) // { movementMask = 0; rotation = 0; bullet = bullets[i]; if (bullets[i]->Active()) { inactive = 0; // use the map element from the last position level = bullet->yRoom; column = bullet->zRoom; row = bullet->xRoom; mapArray = map->GetMapArray(level,row,column); bullet->MoveForward(); bulletsSubX = bullet->X; bulletsSubY = bullet->Y; bulletsSubZ = bullet->Z; /* if (!mapArray->adjacentBlock[AS_MAP_UP]) // up if (bulletsSubX < AS_BULLET_NOSE) inactive = 1; if (!mapArray->adjacentBlock[AS_MAP_DOWN]) // down if (bulletsSubX > lengthMinusNose) inactive = 1; // Check Z if (!mapArray->adjacentBlock[AS_MAP_LEFT]) // left if (bulletsSubZ < AS_BULLET_NOSE) inactive = 1; if (!mapArray->adjacentBlock[AS_MAP_RIGHT]) // right if (bulletsSubZ > lengthMinusNose) inactive = 1; if (inactive) { bullets[i]->active = 0; continue; } */ int direction = -1; if (bulletsSubX < 0) movementMask |= 0x01; if (bulletsSubX >= AS_MAP_ROOM_LENGTH) movementMask |= 0x02; if (bulletsSubZ < 0) movementMask |= 0x04; if (bulletsSubZ >= AS_MAP_ROOM_LENGTH) movementMask |= 0x08; int loops = 1; if (movementMask == 0) loops = 0; // no change in block if ((movementMask == 5) || (movementMask == 6) || (movementMask == 9) || (movementMask == 10)) loops = 2; // takes care of diagonal jump lastBlockStairStatus = mapArray->stairInfo; for (int loop = 0; loop < loops; loop++) { int notfound = 1; int checkDirection; for (checkDirection = 0; checkDirection < 4; checkDirection++) { if (movementMask & (1 << checkDirection)) { newDirection = map->ConvertDirection(checkDirection,rotation); // if passed through a link, may need to rotate 2nd in loop if (mapArray->adjacentBlock[newDirection] > 0) { direction = newDirection; movementMask &=~(1 << newDirection); // ignore next time notfound = 0; break; // from checkDirection loop } } } if (notfound) { inactive = 1; break; // from loop loop } 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); #ifdef _AS_VERSION_PC bullet->Turn(-rotation); #else bullet->Turn(rotation); #endif } } 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; } } mapArray = map->GetMapArray(level,row,column); currentBlockStairStatus = mapArray->stairInfo; switch(direction) // this could be optimised but it would be difficult to follow { case AS_MAP_UP: // note that signs are reversed compared to GroundSearch2, it is offset, not base { if (currentBlockStairStatus == AS_MAP_STAIRS_UPTODOWN) bulletsSubY += AS_MAP_ROOM_LENGTH; if (lastBlockStairStatus == AS_MAP_STAIRS_DOWNTOUP) bulletsSubY -= AS_MAP_ROOM_LENGTH; break; } case AS_MAP_DOWN: { if (currentBlockStairStatus == AS_MAP_STAIRS_DOWNTOUP) bulletsSubY += AS_MAP_ROOM_LENGTH; if (lastBlockStairStatus == AS_MAP_STAIRS_UPTODOWN) bulletsSubY -= AS_MAP_ROOM_LENGTH; break; } case AS_MAP_LEFT: { if (currentBlockStairStatus == AS_MAP_STAIRS_LEFTTORIGHT) bulletsSubY += AS_MAP_ROOM_LENGTH; if (lastBlockStairStatus == AS_MAP_STAIRS_RIGHTTOLEFT) bulletsSubY -= AS_MAP_ROOM_LENGTH; break; } case AS_MAP_RIGHT: { if (currentBlockStairStatus == AS_MAP_STAIRS_RIGHTTOLEFT) bulletsSubY += AS_MAP_ROOM_LENGTH; if (lastBlockStairStatus == AS_MAP_STAIRS_LEFTTORIGHT) bulletsSubY -= AS_MAP_ROOM_LENGTH; break; } } lastBlockStairStatus = currentBlockStairStatus; } if (inactive) { bullet->Reset(); continue; } /* if (bulletsSubX < 0) direction = AS_MAP_UP; if (bulletsSubX >= AS_MAP_ROOM_LENGTH) direction = AS_MAP_DOWN; if (bulletsSubZ < 0) direction = AS_MAP_LEFT; if (bulletsSubZ >= 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); bullets[i]->Turn(-rotation); } } 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 (bulletsSubX >= AS_MAP_ROOM_LENGTH) bulletsSubX -= AS_MAP_ROOM_LENGTH; if (bulletsSubZ >= AS_MAP_ROOM_LENGTH) bulletsSubZ -= AS_MAP_ROOM_LENGTH; if (bulletsSubX < 0) bulletsSubX += AS_MAP_ROOM_LENGTH; if (bulletsSubZ < 0) bulletsSubZ += AS_MAP_ROOM_LENGTH; //mapArray = map->GetMapArray(level,row,column); //bulletsSubY = 0; switch (mapArray->stairInfo) { case AS_MAP_STAIRS_LEFTTORIGHT: { if ((bulletsSubY < bulletsSubZ) || (bulletsSubY > (bulletsSubZ + AS_MAP_ROOM_LENGTH))) inactive = 1; break; } case AS_MAP_STAIRS_RIGHTTOLEFT: { if ((bulletsSubY < (AS_MAP_ROOM_LENGTH - bulletsSubZ)) || (bulletsSubY > ((2 *AS_MAP_ROOM_LENGTH) - bulletsSubZ))) inactive = 1; break; } case AS_MAP_STAIRS_UPTODOWN: { if ((bulletsSubY < bulletsSubX) || (bulletsSubY > (bulletsSubX + AS_MAP_ROOM_LENGTH))) inactive = 1; break; } case AS_MAP_STAIRS_DOWNTOUP: { if ((bulletsSubY < (AS_MAP_ROOM_LENGTH - bulletsSubX)) || (bulletsSubY > ((2 *AS_MAP_ROOM_LENGTH) - bulletsSubX))) inactive = 1; break; } } if (inactive) { bullet->Reset(); continue; } if (rotation) { #ifdef _AS_VERSION_PC rotationMatrix.Initialize(); rotationMatrix.Rotate(0,-rotation,0); vector.X = bulletsSubX - 1000; vector.Y = bulletsSubY - 1000; vector.Z = bulletsSubZ - 1000; rotationMatrix.Transform(vector); bulletsSubX = vector.Tx + 1000 + 0.5; bulletsSubY = vector.Ty + 1000 + 0.5; bulletsSubZ = vector.Tz + 1000 + 0.5; #else ResetMatrix(rotationMatrix.m); rotationVector.vx = 0; rotationVector.vy = -rotation; rotationVector.vz = 0; RotMatrix(&rotationVector,&rotationMatrix); inputVector.vx = bulletsSubX - 1000; inputVector.vy = bulletsSubY - 1000; inputVector.vz = bulletsSubZ - 1000; ApplyMatrix(&rotationMatrix,&inputVector,&outputVector); bulletsSubX = outputVector.vx + 1000;// + 0.5; bulletsSubY = outputVector.vy + 1000;// + 0.5; bulletsSubZ = outputVector.vz + 1000;// + 0.5; //bullet->rotate(0,newRotation,0); #endif } bullet->SetPosition(bulletsSubX, bulletsSubY, bulletsSubZ); bullet->xRoom = row; bullet->yRoom = level; bullet->zRoom = column; } // active //} // i % 5 } // i } void AsBulletManager::SetFeatures(AsArenaBuilder *_map,AsPlayer *_player) { map = _map; player = _player; } AsBullet *AsBulletManager::FindInactiveBullet() { for (int i = 0; i < AS_MAX_BULLETS; i++) { if (!bullets[i]->Active()) return(bullets[i]); } return(0); } AsBullet::AsBullet() { Reset(); } void AsBullet::Reset() { /* X = 1000; // all this is irrelevant really Y = 1000; Z = 1000;//3000.0; xRoom = 4; yRoom = 4; zRoom = 1; oldX = X; oldY = Y; oldZ = Z; aroundX = 0;//AS_DEGREES_45; aroundY = 0;//AS_DEGREES_45; aroundZ = 0;//AS_DEGREES_45; */ active = 0; fromPlayer = 0; } void AsBullet::Fire(int playerX, int playerY, int playerZ,int turnAngle,int lookAngle ,int xBlock,int yBlock,int zBlock) { active = 1; aroundY = turnAngle; aroundX = lookAngle; X = playerX; Y = playerY; Z = playerZ; xRoom = xBlock; yRoom = yBlock; zRoom = zBlock; } void AsBullet::Move(unsigned int turnAngle,unsigned int lookAngle) { #ifdef _AS_VERSION_PC X += (int)(SIN(turnAngle) * AS_BULLET_MOVE_FACTOR); Z += (int)(COS(turnAngle) * AS_BULLET_MOVE_FACTOR); Y += (int)(SIN(-lookAngle) * AS_BULLET_MOVE_FACTOR); #else MATRIX matTmp; SVECTOR startVector; SVECTOR rotation; SVECTOR currentDirection; startVector.vx = 0; startVector.vy = 0; startVector.vz = ONE; rotation.vx = lookAngle; rotation.vy = -turnAngle; rotation.vz = 0; aroundY = turnAngle; RotMatrix( &rotation,&matTmp ) ; // multiply startVector by mattmp and put the result in currentDirection // which is the vector defining the direction the player is pointing ApplyMatrixSV(&matTmp,&startVector,¤tDirection); // currentDirection components have a maximum value of 4096 so we // scale nD to 4096 /nD then when we add the amount of // translation we divide by nD. This ensures that we will translate // the number of units originally specified by nD // nD = 4096 /nD ; X +=(currentDirection.vx * 250 ) / 4096; Y +=(currentDirection.vy * 250 ) / 4096; Z +=(currentDirection.vz * 250 ) / 4096; #endif } void AsBullet::MoveForward() { Move(aroundY,aroundX); } void AsBullet::Turn(int angle) { aroundY += angle; } void AsBullet::StoreOldPosition() { oldX = X; oldY = Y; oldZ = Z; } void AsBullet::SetPosition(int newX, int newY, int newZ) { X = newX; Y = newY; Z = newZ; }