Skip to navigation

3D objects: PlaceObjectOnTile

Name: PlaceObjectOnTile [Show more] Type: Subroutine Category: 3D objects Summary: Place an object on a tile, putting it on top of any existing boulders or towers
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * AddEnemiesToTiles calls PlaceObjectOnTile * PlaceObjectBelow calls PlaceObjectOnTile * ProcessActionKeys (Part 2 of 2) calls PlaceObjectOnTile * SpawnPlayer calls PlaceObjectOnTile

This routine sets the following (if successful): * X-th entry in (xObject, yObject, zObject) is set to the 3D coordinate of the newly added object, where the y-coordinate is yObject(Hi Lo) * X-th entry in objectFlags, bit 7 is clear to indicate that object #X has been allocated to an object * X-th entry in objectFlags, bit 6 is set if we add the object on top of a boulder or tower (and the object number of the boulder/tower is in bits 0-5) * X-th entry in yObjectLo = 224, so objects are spawned at a height of 224 above the tile itself, or 0.875 tile widths (this is used for the gaze vector calculations, so this is effectively the height of the object's eyes above the tile) * X-th entry in objectPitchAngle = -11, so objects look slightly downwards at a pitch angle of 15.5 degrees * X-th entry in objectYawAngle is set to a multiple of 11.25 degrees, as determined by the next seed * tileData for the tile is set to the object number in X in bits 0 to 5, and bits 6 and 7 are set to indicate that the tile contains an object
Arguments: X The number of the object to add to the tile (xTile, zTile) The tile coordinate where we place the object
Returns: C flag Status flag: * Clear if we successfully added the object to the tile * Set if we failed to add the object to the tile (if the tile is occupied by an object that is not a a boulder or tower, for example)
.PlaceObjectOnTile LDA xTile \ Set the 3D coordinate for object #X to (xTile, zTile) STA xObject,X \ by updating the X-th entries in the xObject and LDA zTile \ zObject tables STA zObject,X \ \ So this sets the x- and z-coordinates of the 3D \ coordinate for our object; we set the y-coordinate \ later JSR GetTileData \ Set A to the tile data for the tile anchored at \ (xTile, zTile), setting the C flag if the tile \ contains an object \ \ This also sets the tile page in tileDataPage and the \ tile number in Y, so tileDataPage+Y now points to the \ tile data entry in the tileData table BCC objt4 \ If the C flag is clear then this tile does not already \ have an object placed on it, so jump to objt4 to place \ object #X on the tile STY tileNumber \ Store the tile number in tileNumber so we can refer to \ it later AND #%00111111 \ Because the tile has an object on it, the tile data TAY \ contains the number of the top object on the tile in \ bits 0 to 5, so extract the object number into Y (so \ the tile effectively contains object #Y) LDA objectTypes,Y \ Set A to the type of object that's already on the tile \ (i.e. the type of object #Y) CMP #3 \ If the tile contains a boulder (an object of type 3), BEQ objt1 \ jump to objt1 to put the new object on top of the \ boulder CMP #6 \ If the tile doesn't contain the Sentinel's tower (type BNE objt6 \ 6) then it must contain an object on which we can't \ place our new object, so jump to objt6 to return from \ the subroutine without adding the object to the tile .objt1 \ If we get here then the object already on the tile is \ either a boulder (type 3) or the Sentinel's tower \ (type 6) \ \ In either case, we want to place our object on top of \ the object that is already there, which we can do by \ setting bit 6 of the object flags for the new object \ and putting the number of the existing object into \ bits 0 to 5 TYA \ Set the object flags for the object that we are adding ORA #%01000000 \ (i.e. object #X) so that bit 6 is set, and bits 0 to 5 STA objectFlags,X \ contain the number of the object that is already on \ the tile \ \ This denotes that our new object, object #X, is on top \ of object #Y LDA objectTypes,Y \ If the object that's already on the tile is not the CMP #6 \ Sentinel's tower (type 6), jump to objt2 BNE objt2 \ If we get here then we are placing object #X on top of \ the Sentinel's tower (type 6) in object #Y \ \ The next task is to calculate the altitude of the \ object when it is placed on top of the tower (i.e. the \ y-coordinate of the object, as the y-axis goes up and \ down in our 3D world) \ \ The tower is defined with a height of one coordinate \ (where a tile-sized cube is one coordinate across) \ \ Object y-coordinates are stored as 16-bit numbers in \ the form yObject(Hi Lo), with the low byte effectively \ acting like a fractional part, so to work out the \ y-coordinate for the object we are placing on top of \ the boulder, we need to add (1 0) to the tower's \ current y-coordinate, like this: \ \ yObject,X = yObject,Y + (1 0) \ \ We need to do this calculation for both bytes, \ starting with the low byte LDA yObjectLo,Y \ First we add the low bytes, by adding 0 to the Y-th STA yObjectLo,X \ entry in yObjectLo and storing this in the low byte of \ the X-th entry in yObjectLo (which we can do by simply \ copying the Y-th entry into the X-th entry) CLC \ Clear the C flag and set A = 1 so the addition at LDA #1 \ objt3 will do the following: \ \ A = yObjectHi,Y + 1 \ \ This will add the high bytes of the calculation to \ give the result we want: \ \ (A yObjectLo,X) = (yObjectHi,Y yObjectLo,Y) + (1 0) \ \ = ((yObjectHi,Y + 1) yObjectLo,Y) \ \ with the subsequent jump to objt5 storing A in \ yObjectHi,X as required BNE objt3 \ Jump to objt3 to do the calculation (this BNE is \ effectively a JMP as A is never zero) .objt2 \ If we get here then we are placing our new object #X \ on top of the boulder (type 3) in object #Y \ \ The next task is to calculate the altitude of the \ object when it is placed on top of the boulder (i.e. \ the y-coordinate of the object, as the y-axis goes up \ and down in our 3D world) \ \ Boulders are defined with a height of 0.5 coordinates \ (where a tile-sized cube is one coordinate across) \ \ Object y-coordinates are stored as 16-bit numbers in \ the form yObject(Hi Lo), with the low byte effectively \ acting like a fractional part, so to work out the \ y-coordinate for the object we are placing on top of \ the boulder, we need to add (0 128) to the boulder's \ current y-coordinate, like this: \ \ yObject,X = yObject,Y + (0 128) \ \ We need to do this calculation for both bytes, \ starting with the low byte LDA yObjectLo,Y \ First we add the low bytes, by adding 128 to the Y-th CLC \ entry in yObjectLo and storing this in the low byte of ADC #128 \ the result in the X-th entry in yObjectLo STA yObjectLo,X LDA #0 \ Set A = 0 so the following addition will add the high \ bytes to give the result we want: \ \ (A yObjectLo,X) = (yObjectHi,Y yObjectLo,Y) \ + (0 128) \ \ = (yObjectHi,Y (yObjectLo,Y + 128)) \ \ with the subsequent jump to objt5 storing A in \ yObjectHi,X as required .objt3 ADC yObjectHi,Y \ Add A to the high byte of the y-coordinate of the \ object beneath the one we are adding and store the \ result in A \ \ So (A yObjectLo,X) now contains the y-coordinate of \ the new object that we are placing on top of the \ boulder or tower LDY tileNumber \ Set Y to the tile number where we are adding the \ object, which we stored above JMP objt5 \ Jump to objt5 to store A as the y-coordinate of the \ new object on the tile, and update the various other \ object and tile tables for the new object .objt4 PHA \ Store the tile data for the tile on the stack so we \ can retrieve it below LDA #0 \ Clear bit 7 of the object's flags to indicate that STA objectFlags,X \ object #X is allocated to an object LDA #224 \ Set the object's entry in yObjectLo to 224 STA yObjectLo,X \ \ This places objects well above the tile, at a height \ of 224 / 256 = 0.875 coordinates above the tile itself \ \ This is used for the gaze vector calculations, so this \ is effectively the height of the object's eyes above \ the tile PLA \ Set A to the tile data for the tile, which we stored \ on the stack above LSR A \ The top nibble of the tile data contains the tile LSR A \ altitude, so this sets A to the tile altitude LSR A LSR A \ We now fall through into objt5 to set the tile \ y-coordinate for object #X to the tile altitude in A .objt5 STA yObjectHi,X \ Set the high byte of the 3D y-coordinate for object #X \ to the value of A by updating the X-th entry in the \ yObjectHi table \ \ We now have a full 3D coordinate for the object in \ (xObject, yObject, zObject), where yObject is stored \ as a 16-bit number in yObject(Hi Lo) TXA \ Set the tile data for this tile to object number X, ORA #%11000000 \ with bits 6 and 7 set to indicate that the tile now STA (tileDataPage),Y \ contains an object LDA #&F5 \ Set the object's pitch angle to -11, so the object STA objectPitchAngle,X \ looks down slightly at a pitch angle of 15.5 degrees \ (as 360 * 11 / 256 = 15.5) \ We now calculate the object's yaw angle, which \ determines the direction in which it is facing \ \ The degree system in the Sentinel looks like this: \ \ 0 \ -32 | +32 Overhead view of object \ \ | / \ \ | / 0 = looking straight ahead \ \|/ +64 = looking sharp right \ -64 -----+----- +64 -64 = looking sharp left \ /|\ \ / | \ \ / | \ \ -96 | +96 \ 128 \ \ In this context, looking straight ahead means the \ object is looking into the screen, towards the back of \ the landscape JSR GetNextSeedNumber \ Set A to the next number from the landscape's sequence \ of seed numbers AND #%11111000 \ Convert A to be a multiple of 8 and in the range 0 to \ 248 (i.e. 0 to 31 * 8) \ \ This rotates the object so it is looking along one of \ 32 fixed rotations, each of which is a multiple of \ 11.25 degrees CLC \ Set A = A + 96 ADC #96 \ \ This doesn't change the fact that A is a multiple of \ 11.25 degrees, so it's presumably intended to make the \ player's rotation work well on the starting level STA objectYawAngle,X \ Set the object's objectYawAngle to the angle we just \ calculated in A CLC \ Clear the C flag to indicate that we have successfully \ added the object to the tile RTS \ Return from the subroutine .objt6 \ If we get here then the tile already contains an \ object and that object is not a boulder (type 3) or \ tower (type 6), so we can't add the new object to the \ tile SEC \ Set the C flag to indicate that we have failed to add \ the object to the tile RTS \ Return from the subroutine