Skip to navigation

Maths (Geometry): FollowGazeVector (Part 1 of 5)

Name: FollowGazeVector (Part 1 of 5) [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Follow a gaze vector from a viewing object to determine whether the viewer can see a flat tile or platform (i.e. boulder or tower)
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * CheckEnemyGaze (Part 2 of 2) calls FollowGazeVector * ProcessActionKeys (Part 1 of 2) calls FollowGazeVector

This routine follows the gaze of a viewing object to see if it hits a tile or a platform (where a platform is a boulder or the Sentinel's tower) The gaze is defined by the following vector: [ xVector ] [ xVector(Lo Bot) ] [ yVector ] = [ yVector(Lo Bot) ] [ zVector ] [ zVector(Lo Bot) ] This contains the gaze vector, scaled down to be very small, so we can trace the line of the gaze by repeatedly adding this vector to the coordinates of the viewing object to step along the line of the gaze. At each step we check to see whether the gaze has hit a tile, repeating this until we either hit a tile or fall off the edge of the landscape.
Arguments: viewingObject The number of the object that is performing the gaze xVector(Lo Bot) The x-coordinate of the scaled-down gaze vector yVector(Lo Bot) The y-coordinate of the scaled-down gaze vector zVector(Lo Bot) The z-coordinate of the scaled-down gaze vector enemyCheckingRobot Set bit 7 if this routine is being called when an enemy is checking to see if it can see a robot object (i.e. in the CheckEnemyGaze routine) targetObject The target object
Returns: C flag Status flag: * Clear if the viewing object can see a tile along the gaze vector (or, if enemyCheckingRobot is set, if the viewing object can see a robot) * Set if the viewing object can't see a tile along the gaze vector targetOnTile Records whether the gaze vector can see a tile containing the target object: * Bit 7 clear = gaze vector cannot see the target object * Bit 7 set = gaze vector can see the target object gazeCanSeeTree Records whether the gaze vector can see a tree: * Bit 7 clear = gaze vector cannot see a tree * Bit 7 set = gaze vector can see a tree xCoordHi The tile x-coordinate of the tile that can be seen zCoordHi The tile z-coordinate of the tile that can be seen
.FollowGazeVector LDX viewingObject \ Set X to the number of the object that is performing \ the gaze (i.e. doing the looking or scanning) LSR targetOnTile \ Clear bit 7 of targetOnTile so it can be set if the \ tile contains the target object whose number is in \ targetObject LSR gazeCanSeeTree \ Clear bit 7 of gazeCanSeeTree so it can be set if \ there is tree on the tile that can be seen by the \ gaze vector JSR GetObjectCoords \ Fetch the cartesian coordinates of the viewing object \ as three 24-bit numbers, as follows: \ \ xCoord(Hi Lo Bot) \ \ yCoord(Hi Lo Bot) \ \ zCoord(Hi Lo Bot) \ \ We now repeatedly add the scaled-down gaze vector to \ this coordinate to step along the gaze from the \ viewing object and see if it hits anything .gaze1 JSR AddVectorToCoord \ Add the coordinates and the vector as follows: \ \ [ xCoord ] [ xCoord ] [ xVector ] \ [ yCoord ] = [ yCoord ] + [ yVector ] \ [ zCoord ] [ zCoord ] [ zVector ] \ \ where: \ \ [ xCoord ] [ xCoord(Hi Lo Bot) ] \ [ yCoord ] = [ yCoord(Hi Lo Bot) ] \ [ zCoord ] [ zCoord(Hi Lo Bot) ] \ \ and: \ \ [ xVector ] [ xVector(Lo Bot) ] \ [ yVector ] = [ yVector(Lo Bot) ] \ [ zVector ] [ zVector(Lo Bot) ] \ \ This adds the scaled-down gaze vector to the \ coordinate to perform a step along the object's gaze LDA xCoordHi \ Set xTile to the high byte of the result (i.e. the STA xTile \ tile x-coordinate below our current position along the \ viewer's gaze) CMP #31 \ If we just stepped beyond the right edge of the BCS gaze4 \ landscape then the gaze does not land upon a tile, so \ jump to gaze4 to return from the subroutine with the \ C flag set to indicate that the viewer is not looking \ at a tile LDA zCoordHi \ Set zTile to the high byte of the result (i.e. the STA zTile \ tile z-coordinate below our current position along the \ viewer's gaze) CMP #31 \ If we just stepped beyond the rear edge of the BCS gaze4 \ landscape then the gaze does not land upon a tile, so \ jump to gaze4 to return from the subroutine with the \ C flag set to indicate that the viewer is not looking \ at a tile LDA #%10000000 \ Set bit 7 and clear bit 6 of considerObjects so the STA considerObjects \ following call to GetTileAltitude will include trees \ and platform objects in its calculations STA yAccuracyLo \ Set yAccuracyLo = 128, so by default the gaze vector \ has to be no more than half a tile's height above a \ tile for us to consider it as potentially seeing the \ tile (this figure is changed for the Sentinel's tower \ to make the player have to be much more accurate when \ trying to view the Sentinel's tile) LDA #0 \ Set yPlatformLo = 0, so if the tile doesn't contain STA yPlatformLo \ a platform, yPlatformLo will be zero STA boulderOnTile \ Clear bit 7 of boulderOnTile to denote that the tile \ does not contain a boulder, so GetTileAltitude can \ set bit 7 if it does contain a boulder JSR GetTileAltitude \ Call GetTileAltitude with bit 7 of considerObjects \ set to extract the following tile data: \ \ * (A yPlatformLo) = if the tile contains a boulder \ or the Sentinel's tower, then this is set to the \ altitude of the platform object, plus 32 for the \ tower or plus 96 for the boulder \ \ * A = if the tile contains a non-platform object \ then this is set to the high byte of the \ tile's altitude, which is the same as the high \ byte of the object's altitude \ \ * A = if the tile is not flat then this is set to \ the tile altitude from the tile data \ \ * C flag = the tile's shape, clear if the tile is \ flat or set if the tile is not flat \ \ * boulderOnTile has bit 7 set if the tile contains a \ boulder \ \ * considerObjects has bit 6 if the tile contains a \ boulder or the Sentinel's tower and the current \ position along the gaze vector is not within the \ platform object (so the gaze vector is passing \ close by the platform object but is not hitting \ it) \ \ * yAccuracyLo is changed from 128 to 16 if the tile \ contains the Sentinel's tower and the gaze vector \ is pointing at the sides of the tower BCS gaze5 \ If the tile is not flat, jump to gaze5 to calculate \ the gaze vector's interaction with the tile slopes \ If we get here then the tile is flat and may contain \ an object TAX \ Set (X A) to the altitude of the platform (if there is LDA yPlatformLo \ one) or the altitude of the tile (is there isn't) SEC \ Set the following: SBC yCoordLo \ STA yPlatformLo \ (A yPlatformLo) = (X A) - yCoord(Hi Lo) TXA \ SBC yCoordHi \ So this contains the relative altitude of the tile or \ platform compared to our current position along the \ viewer's gaze (as we are subtracting the altitude of \ the gaze from the altitude of the tile/platform) BMI gaze1 \ If the high byte of the result is negative then the \ gaze is passing through the y-coordinate above the \ tile or platform, in terms of whole numbers (so it is \ essentially more than one "tile cube" above the tile) \ \ This means it hasn't hit the tile and is still passing \ through empty space above the landscape, so loop back \ to gaze1 to move along the gaze vector and restart the \ checks BNE gaze4 \ If the high byte of the result is non-zero and \ positive, then the gaze is passing through the \ y-coordinate below the tile or platform, in terms of \ whole numbers (so it is essentially in the "tile cube" \ beneath the tile) \ \ This means the gaze must have passed through a slope \ and "into" the ground beneath the tile, so jump to \ gaze4 to return from the subroutine with the C flag \ set to indicate that the viewer is not looking at a \ tile \ If we get here then the gaze is currently sitting \ within the "tile cube" above the tile LDA yPlatformLo \ If yPlatformLo >= yAccuracyLo, then the vertical CMP yAccuracyLo \ distance between the gaze and the platform is greater BCS gaze4 \ than the accuracy specified in yAccuracyLo, so jump to \ gaze4 to return from the subroutine with the C flag \ set to indicate that the viewer is not looking at a \ tile or object \ \ Note that yAccuracyLo = 128 for all tiles (i.e. no \ more than 0.5 of a tile's height above the tile) apart \ from the tile containing the Sentinel's tower, when it \ is reduced to 16 if the gaze vector is pointing at the \ sides of the tower (i.e. no more than 0.025 of a \ tile's height above the tile) \ \ This makes the player have to be much more accurate \ when trying to view the Sentinel's tile BIT considerObjects \ If bit 6 of considerObjects is set then the tile BVS gaze4 \ contains a boulder or the Sentinel's tower and the \ current position along the gaze vector is not within \ the platform object (so the gaze vector is passing \ close by the platform object but is not hitting it), \ so jump to gaze4 to return from the subroutine with \ the C flag set to indicate that the viewer is not \ looking at a tile, as the platform will be at least \ partially obscuring any tiles that are visible to the \ sides of the boulder or tower LDA enemyCheckingRobot \ If bit 7 is set in either of enemyCheckingRobot and ORA boulderOnTile \ boulderOnTile, skip the following test, as we do not BMI gaze2 \ care if the gaze is upwards when either of the \ following is true: \ \ * This is an enemy is looking for a robot, in which \ case we are still interested even if the enemy is \ below the robot and can't see the tile that the \ robot is on \ \ * We are looking at a boulder, in which case it can \ still be above us and a suitable target for an \ action (as we can create or absorb from a boulder \ stack by looking at any of the boulders on the \ stack, even if they are above us) \ If we get here then neither of the above special cases \ are true, so we now check whether the viewer is \ looking upwards, as that will mean they can't see down \ onto the tile LDA yVectorLo \ If the low byte (i.e. the fractional part) of the gaze BPL gaze4 \ vector's y-coordinate is positive, then the viewer is \ looking upwards and therefore can't see down onto the \ tile, so jump to gaze4 to return from the subroutine \ with the C flag set to indicate that the viewer is not \ looking at a tile .gaze2 \ If we get here then the viewer's gaze has landed on a \ tile, so the final check is to make sure the viewer is \ not looking at their own tile LDX viewingObject \ Set X to the number of the object that is performing \ the gaze (i.e. doing the looking or scanning) LDA xTile \ If the x-coordinate of the viewing object is not the CMP xObject,X \ same as the x-coordinate of the tile that the gaze has BNE gaze3 \ hit, jump to gaze3 to return from the subroutine with \ the C flag clear, to indicate that the viewer is \ looking at a tile \ If we get here then the x-coordinates match, so we now \ need to check the z-coordinates LDA zTile \ If the z-coordinate of the viewing object is the same CMP zObject,X \ as the x-coordinate, then the viewer is looking at BEQ gaze1 \ their own tile, so loop back to gaze1 to move along \ the gaze vector and restart the checks \ If we get here then the z-coordinates do not match, so \ we can now return from the subroutine with the C flag \ clear, to indicate that the viewer is looking at a \ tile .gaze3 CLC \ Set the C flag to indicate that the gaze hit \ something, so the viewing object is looking at \ something RTS \ Return from the subroutine .gaze4 SEC \ Set the C flag to indicate that the gaze didn't hit \ anything, so the viewing object isn't looking at \ anything RTS \ Return from the subroutine