// // Stairs. // #include "game.h" #include "id.h" #include "stair.h" // // The bounding box of the building. // UBYTE STAIR_x1; UBYTE STAIR_z1; UBYTE STAIR_x2; UBYTE STAIR_z2; // // The height of the roof of the building, 1 + the height of // the highest storey. // UBYTE STAIR_roof_height; // // The maximum dimensions of the bounding box. // This must be a multiple of 8. // #define STAIR_MAX_SIZE 32 // // The array where we store the positions of the stairs. // // // NB. Both flags can be set at once! // // in building.h //#define STAIR_FLAG_UP (1 << 0) // The staircase goes up //#define STAIR_FLAG_DOWN (1 << 1) // The staircase goes down. typedef struct { UBYTE flag; UBYTE up; // The storey you go up to (if (flag & STAIR_FLAG_UP)) UBYTE down; // The storey you go down to (if (flag & STAIR_FLAG_DOWN)) UBYTE x1; UBYTE z1; UBYTE x2; UBYTE z2; } STAIR_Stair; #define STAIR_MAX_STAIRS 32 STAIR_Stair STAIR_stair[STAIR_MAX_STAIRS]; SLONG STAIR_stair_upto; // // The info for each storey. // #define STAIR_MAX_PER_STOREY 3 typedef struct { SLONG handle; // How the storey is identified. UBYTE opp_x1; // A wall is it good to have a staircase opposite on. UBYTE opp_z1; UBYTE opp_x2; UBYTE opp_z2; UBYTE height; UBYTE stair[STAIR_MAX_PER_STOREY]; // Indices into the STAIR_stair array. 0 => NULL index. UBYTE square[STAIR_MAX_SIZE][STAIR_MAX_SIZE / 8]; } STAIR_Storey; #define STAIR_MAX_STOREYS 32 STAIR_Storey STAIR_storey[STAIR_MAX_STOREYS]; SLONG STAIR_storey_upto; // // Sets the given square on the given storey. // void STAIR_set_bit(SLONG storey, SLONG x, SLONG z) { SLONG off_x; SLONG off_z; SLONG byte; SLONG bit; ASSERT(WITHIN(storey, 0, STAIR_storey_upto - 1)); ASSERT(WITHIN(x, STAIR_x1, STAIR_x2 - 1)); ASSERT(WITHIN(z, STAIR_z1, STAIR_z2 - 1)); off_x = x - STAIR_x1; off_z = z - STAIR_z1; ASSERT(WITHIN(off_x, 0, STAIR_MAX_SIZE - 1)); ASSERT(WITHIN(off_z, 0, STAIR_MAX_SIZE - 1)); byte = off_x >> 3; bit = off_x & 7; STAIR_storey[storey].square[off_z][byte] |= (1 << bit); } UBYTE STAIR_get_bit(SLONG storey, SLONG x, SLONG z) { SLONG off_x; SLONG off_z; SLONG byte; SLONG bit; ASSERT(WITHIN(storey, 0, STAIR_storey_upto - 1)); ASSERT(WITHIN(x, STAIR_x1, STAIR_x2 - 1)); ASSERT(WITHIN(z, STAIR_z1, STAIR_z2 - 1)); off_x = x - STAIR_x1; off_z = z - STAIR_z1; ASSERT(WITHIN(off_x, 0, STAIR_MAX_SIZE - 1)); ASSERT(WITHIN(off_z, 0, STAIR_MAX_SIZE - 1)); byte = off_x >> 3; bit = off_x & 7; return STAIR_storey[storey].square[off_z][byte] & (1 << bit); } UBYTE STAIR_get_bit_from_square(UBYTE square[STAIR_MAX_SIZE][STAIR_MAX_SIZE / 8], SLONG x, SLONG z) { SLONG off_x; SLONG off_z; SLONG byte; SLONG bit; ASSERT(WITHIN(x, STAIR_x1, STAIR_x2 - 1)); ASSERT(WITHIN(z, STAIR_z1, STAIR_z2 - 1)); off_x = x - STAIR_x1; off_z = z - STAIR_z1; ASSERT(WITHIN(off_x, 0, STAIR_MAX_SIZE - 1)); ASSERT(WITHIN(off_z, 0, STAIR_MAX_SIZE - 1)); byte = off_x >> 3; bit = off_x & 7; return square[off_z][byte] & (1 << bit); } // // For working out the inside squares on each floor of the building. // // // For ENTER link types, the square field is the first x-line that // the wall encloses a complete square. For a LEAVE link, square is // the last x-line that the wall encloses a complete square. // #define STAIR_LINK_T_ENTER 1 #define STAIR_LINK_T_LEAVE 2 typedef struct { UBYTE next; UBYTE square; UWORD pos; // 8-bit fixed point. } STAIR_Link; #define STAIR_MAX_LINKS 128 STAIR_Link STAIR_link[STAIR_MAX_LINKS]; SLONG STAIR_link_upto; // // One linked list per z-row of floor square. // 0 is the NULL index // UBYTE STAIR_edge[STAIR_MAX_SIZE]; // // How to access the EDGE list. It is relative to // the bounding box, so it takes up less memory. // #ifndef NDEBUG #define STAIR_EDGE(z) (STAIR_check_edge((z)), STAIR_edge[(z) - STAIR_z1]) #else #define STAIR_EDGE(z) (STAIR_edge[(z) - STAIR_z1]) #endif void STAIR_check_edge(SLONG z) { SLONG sz; ASSERT(WITHIN(z, STAIR_z1, STAIR_z2 - 1)); sz = z - STAIR_z1; ASSERT(WITHIN(sz, 0, STAIR_MAX_SIZE - 1)); } // // Random numbers for the STAIR module. // ULONG STAIR_rand_seed; inline void STAIR_srand(ULONG seed) { STAIR_rand_seed = seed; } inline ULONG STAIR_grand(void) { return STAIR_rand_seed; } inline UWORD STAIR_rand(void) { UWORD ans; STAIR_rand_seed *= 328573; STAIR_rand_seed += 123456789; ans = STAIR_rand_seed >> 7; return ans; } // // Adds the stair to the given storey. // void STAIR_add_to_storey(SLONG storey, SLONG stair) { SLONG i; ASSERT(WITHIN(storey, 0, STAIR_storey_upto - 1)); ASSERT(WITHIN(stair, 1, STAIR_stair_upto - 1)); for (i = 0; i < STAIR_MAX_PER_STOREY; i++) { if (STAIR_storey[storey].stair[i] == NULL) { STAIR_storey[storey].stair[i] = stair; return; } } // // No more room! // ASSERT(0); } void STAIR_init() { // // Clear the bounding box. // STAIR_x1 = 255; STAIR_z1 = 255; STAIR_x2 = 0; STAIR_z2 = 0; // // Clear the stair and storey array. // STAIR_stair_upto = 1; // 0 is the NULL stair... STAIR_storey_upto = 0; // // Reset the roof height. // STAIR_roof_height = 0; } void STAIR_set_bounding_box(UBYTE x1, UBYTE z1, UBYTE x2, UBYTE z2) { ASSERT(WITHIN(x1, 0, 255)); ASSERT(WITHIN(z1, 0, 255)); ASSERT(WITHIN(x2, 0, 255)); ASSERT(WITHIN(z2, 0, 255)); STAIR_x1 = x1; STAIR_z1 = z1; STAIR_x2 = x2; STAIR_z2 = z2; ASSERT(WITHIN(STAIR_x2 - STAIR_x1, 0, STAIR_MAX_SIZE)); ASSERT(WITHIN(STAIR_z2 - STAIR_z1, 0, STAIR_MAX_SIZE)); } void STAIR_storey_new(SLONG handle, UBYTE height) { SLONG i; STAIR_Storey *st; ASSERT(WITHIN(STAIR_storey_upto, 0, STAIR_MAX_STOREYS - 1)); st = &STAIR_storey[STAIR_storey_upto]; // // Work out the new roof height. // if (STAIR_roof_height < height + 1) { STAIR_roof_height = height + 1; } // // Initialise the new storey. // memset ((UBYTE*)st, 0, sizeof(STAIR_Storey)); st->handle = handle; st->height = height; st->opp_x1 = 0; st->opp_z1 = 0; st->opp_x2 = 0; st->opp_z2 = 0; // // Initialise the link lists with which we calculate // the inside squares of each storey. // for (i = 0; i < STAIR_MAX_SIZE; i++) { STAIR_edge[i] = 0; } // // We don't use link zero because that is the NULL link index. // STAIR_link_upto = 1; // // Next storey... // STAIR_storey_upto += 1; } void STAIR_storey_wall(UBYTE x1, UBYTE z1, UBYTE x2, UBYTE z2, SLONG opposite) { SLONG x; SLONG z; SLONG dx; SLONG dz; SLONG dxdz; SLONG pos; SLONG square; UBYTE link_t; UBYTE next; UBYTE *prev; // // Make sure this wall is inside the bounding rectangle of // the building. // ASSERT(WITHIN(x1, STAIR_x1, STAIR_x2)); ASSERT(WITHIN(z1, STAIR_z1, STAIR_z2)); if (opposite) { STAIR_Storey *st; ASSERT(WITHIN(STAIR_storey_upto - 1, 0, STAIR_MAX_STOREYS - 1)); st = &STAIR_storey[STAIR_storey_upto - 1]; st->opp_x1 = x1; st->opp_z1 = z1; st->opp_x2 = x2; st->opp_z2 = z2; if (x1 > x2) {SWAP(st->opp_x1, st->opp_x2);} if (z1 > z2) {SWAP(st->opp_z1, st->opp_z2);} } if (z1 == z2) { // // Ignore this line because it does not cross any // z-lines. // return; } if (z1 > z2) { link_t = STAIR_LINK_T_ENTER; // // Always go from top to bottom. // SWAP(x1, x2); SWAP(z1, z2); } else { link_t = STAIR_LINK_T_LEAVE; } dx = x2 - x1 << 16; dz = z2 - z1 << 16; dxdz = DIV64(dx, dz); x = x1 << 16; z = z1; while(z < z2) { switch(link_t) { case STAIR_LINK_T_ENTER: pos = x >> 8; // 8-bit fixed point. square = MAX(x, x + dxdz); square += 0xffff; square >>= 16; break; case STAIR_LINK_T_LEAVE: pos = x >> 8; // 8-bit fixed point. square = MIN(x, x + dxdz); square >>= 16; break; default: ASSERT(0); break; } // // Create a new link. // ASSERT(WITHIN(STAIR_link_upto, 1, STAIR_MAX_LINKS - 1)); STAIR_link[STAIR_link_upto].square = square; STAIR_link[STAIR_link_upto].pos = pos; STAIR_link[STAIR_link_upto].next = 0; // // Insert it in the correct place in the linked list. // prev = &STAIR_EDGE(z); next = STAIR_EDGE(z); while(1) { if (next == NULL) { // // We have reached end of the linked list. // break; } ASSERT(WITHIN(next, 1, STAIR_link_upto - 1)); if (STAIR_link[next].pos >= STAIR_link[STAIR_link_upto].pos) { if (STAIR_link[next].pos == STAIR_LINK_T_ENTER) { // // Make the ENTER link appear first in the linked list. // } else { // // This is the right place to insert it. // break; } } // // Go onto the next link. // prev = &STAIR_link[next].next; next = STAIR_link[next].next; } ASSERT(*prev == next); // // Insert it. // STAIR_link[STAIR_link_upto].next = next; *prev = STAIR_link_upto; STAIR_link_upto += 1; // // Do the next line. // x += dxdz; z += 1; } } SLONG STAIR_storey_finish() { SLONG i; SLONG x; SLONG z; SLONG x1; SLONG x2; UBYTE next; UBYTE next1; UBYTE next2; STAIR_Storey *st; ASSERT(WITHIN(STAIR_storey_upto - 1, 0, STAIR_MAX_STOREYS - 1)); st = &STAIR_storey[STAIR_storey_upto - 1]; // // Go through the linked lists and mark each square as // being inside or outside. // for (z = STAIR_z1; z < STAIR_z2; z++) { next = STAIR_EDGE(z); if (next == NULL) { // // This whole z-row is outside. // continue; } // // These should come in pairs. // next1 = next; next2 = STAIR_link[next].next; // // The pairs should be start and end. // if (next1 == NULL || next2 == NULL) { // // An invalid storey. // return FALSE; } ASSERT(WITHIN(next1, 1, STAIR_link_upto - 1)); ASSERT(WITHIN(next2, 1, STAIR_link_upto - 1)); x1 = STAIR_link[next1].square; x2 = STAIR_link[next2].square; // // We only mark squares that are completely inside. // for (x = x1; x < x2; x++) { // // Mark these squares as inside. // STAIR_set_bit(STAIR_storey_upto - 1, x, z); } } return TRUE; } // // Returns whether there is an outside door opening // onto the given square on the given storey. // SLONG STAIR_is_door(SLONG storey, SLONG x, SLONG z) { return 0; } void STAIR_calculate(UWORD seed) { SLONG i; SLONG j; SLONG k; SLONG l; SLONG x; SLONG z; SLONG dx; SLONG dz; SLONG x1; SLONG x2; SLONG z1; SLONG z2; SLONG score; SLONG ox; SLONG oz; SLONG outside; SLONG best_x1; SLONG best_z1; SLONG best_x2; SLONG best_z2; SLONG best_score; STAIR_Storey *st; STAIR_Storey *st_n; STAIR_Stair *ss; STAIR_Stair *ss_new; SLONG dox; SLONG doz; SLONG height; SLONG height_n; UBYTE square[STAIR_MAX_SIZE][STAIR_MAX_SIZE / 8]; UBYTE go_up; UBYTE go_down; // // Randomise the order we do the storeys in. // UBYTE storey_order1[STAIR_MAX_STOREYS]; STAIR_srand(seed); for (i = 0; i < STAIR_MAX_STOREYS; i++) { storey_order1[i] = i; } for (i = 0; i < STAIR_MAX_STOREYS; i++) { j = STAIR_rand() % STAIR_MAX_STOREYS; k = STAIR_rand() % STAIR_MAX_STOREYS; SWAP(storey_order1[j], storey_order1[k]); } // // Workout where the stairs should be for each storey. // for (i = 0; i < STAIR_storey_upto; i++) { st = &STAIR_storey[i]; // // The height of this storey. // height = st->height; for (j = 0; j < STAIR_storey_upto; j++) { // // Look for neighbouring storeys. // st_n = &STAIR_storey[j]; // // The height of this storey. // height_n = st_n->height; if (abs(height - height_n) == 1) { // // This is a neighbouring storey. AND in this storeys // squares. // memcpy(square, st->square, sizeof(square)); for (z = 0; z < STAIR_MAX_SIZE; z++) for (x = 0; x < STAIR_MAX_SIZE / 8; x++) { square[z][x] &= st_n->square[z][x]; } // // Is this storey higher or lower? // go_up = 0; go_down = 0; if (height_n == height + 1) {go_up = 1;} else if (height_n == height - 1) {go_down = 1;} else {ASSERT(0);} // // Is there a staircase on this storey we use? // for (k = 0; k < STAIR_MAX_PER_STOREY; k++) { if (st->stair[k] != NULL) { ASSERT(WITHIN(st->stair[k], 1, STAIR_stair_upto - 1)); ss = &STAIR_stair[st->stair[k]]; // // There is already a staircase on this storey. It is // in an okay place? // if (STAIR_get_bit_from_square(square, ss->x1, ss->z1) && STAIR_get_bit_from_square(square, ss->x2, ss->z2)) { // // We can just use this staircase. // if (go_up) { if (ss->flag & STAIR_FLAG_UP) { // // There is already a staircase up to this floor! // goto placed_stairs; } else { // // Make this staircase go upto the next floor and // create a down staircase on the next floor. // ss->flag |= STAIR_FLAG_UP; ss->up = j; // // New stair... // ss_new = &STAIR_stair[STAIR_stair_upto++]; ss_new->flag = STAIR_FLAG_DOWN; ss_new->down = i; ss_new->x1 = ss->x1; ss_new->z1 = ss->z1; ss_new->x2 = ss->x2; ss_new->z2 = ss->z2; STAIR_add_to_storey(j, STAIR_stair_upto - 1); goto placed_stairs; } } if (go_down) { if (ss->flag & STAIR_FLAG_DOWN) { // // There is already a staircase down to this floor! // goto placed_stairs; } else { // // Make this staircase go down to the next floor and // create a down staircase on the next floor. // ss->flag |= STAIR_FLAG_DOWN; ss->down = j; // // New stair... // ss_new = &STAIR_stair[STAIR_stair_upto++]; ss_new->flag = STAIR_FLAG_UP; ss_new->up = i; ss_new->x1 = ss->x1; ss_new->z1 = ss->z1; ss_new->x2 = ss->x2; ss_new->z2 = ss->z2; STAIR_add_to_storey(j, STAIR_stair_upto - 1); goto placed_stairs; } } } } } // // Does the neighbour have a suitable staircase already? // for (k = 0; k < STAIR_MAX_PER_STOREY; k++) { if (st_n->stair[k] != NULL) { ASSERT(WITHIN(st_n->stair[k], 1, STAIR_stair_upto - 1)); ss = &STAIR_stair[st_n->stair[k]]; // // There is a staircase on this storey. Is is in an // okay place? // if (STAIR_get_bit_from_square(square, ss->x1, ss->z1) && STAIR_get_bit_from_square(square, ss->x2, ss->z2)) { // // We could just use this staircase. // if (go_up) { if (ss->flag & STAIR_FLAG_DOWN) { // // There is staircase going down from the floor above, but // we didn't find a staircase going up! // ASSERT(0); } // // Use this staircase. // ss->flag |= STAIR_FLAG_DOWN; ss->down = i; // // Create a new staircase on this floor. // ss_new = &STAIR_stair[STAIR_stair_upto++]; ss_new->flag = STAIR_FLAG_UP; ss_new->up = j; ss_new->x1 = ss->x1; ss_new->z1 = ss->z1; ss_new->x2 = ss->x2; ss_new->z2 = ss->z2; STAIR_add_to_storey(i, STAIR_stair_upto - 1); goto placed_stairs; } if (go_down) { if (ss->flag & STAIR_FLAG_UP) { // // There is a staircase going up to this floor, but // we didn't find a staircase going down to it! // ASSERT(0); } // // Use this staircase. // ss->flag |= STAIR_FLAG_UP; ss->up = i; // // Create a new staircase on this floor. // ss_new = &STAIR_stair[STAIR_stair_upto++]; ss_new->flag = STAIR_FLAG_DOWN; ss_new->down = j; ss_new->x1 = ss->x1; ss_new->z1 = ss->z1; ss_new->x2 = ss->x2; ss_new->z2 = ss->z2; STAIR_add_to_storey(i, STAIR_stair_upto - 1); goto placed_stairs; } } } } // // Look for the best place for a new staircase in the bounding // box of the building. // best_score = -INFINITY; for (x = STAIR_x1; x < STAIR_x2; x++) for (z = STAIR_z1; z < STAIR_z2; z++) { x1 = x; z1 = z; for (k = 0; k < 4; k++) { x2 = x1; z2 = z1; switch(k) { case 0: x2 += 1; break; case 1: x2 -= 1; break; case 2: z2 += 1; break; case 3: z2 -= 1; break; default: ASSERT(0); break; } if (!WITHIN(x2, STAIR_x1, STAIR_x2 - 1) || !WITHIN(z2, STAIR_z1, STAIR_z2 - 1)) { // // Outside the building! // continue; } // // Make sure these two squares exist on both storeys. // if (STAIR_get_bit_from_square(square, x1, z1) && STAIR_get_bit_from_square(square, x2, z2)) { // // Score this choice of staircase. // score = STAIR_rand() & 0xffff; outside = 0; dx = x2 - x1; dz = z2 - z1; // // If both squares of the staircase are against an outside wall // then that is good. If only one is than that is bad, but not // disasterous. If the staircase is in the way of an outside door // than that is disasterous. // for (l = 0; l < 2; l++) { switch(l) { case 0: ox = x1 + (+dz); oz = z1 + (-dx); break; case 1: ox = x2 + (+dz); oz = z2 + (-dx); break; default: ASSERT(0); break; } if (!WITHIN(ox, STAIR_x1, STAIR_x2 - 1) || !WITHIN(oz, STAIR_z1, STAIR_z2 - 1) || !STAIR_get_bit(i, ox, oz)) { // // (ox,oz) is outside, so this square of the staircase lies // outside of the storey. // outside += 1; if (STAIR_is_door(i, ox, oz)) { // // Arghh! A staircase here would block a door from the // outside. // score = -INFINITY; } } } // // Favour stairs on outside walls. // switch(outside) { case 0: score = 0x0; break; case 1: score -= 0x10000; break; case 2: score += 0x10000; break; default: ASSERT(0); break; } // // We like stairs in corners. // if (x1 == STAIR_x1) {score += 0x5000;} if (x1 == STAIR_x2) {score += 0x5000;} if (x2 == STAIR_x1) {score += 0x5000;} if (x2 == STAIR_x2) {score += 0x5000;} if (z1 == STAIR_z1) {score += 0x5000;} if (z1 == STAIR_z2) {score += 0x5000;} if (z2 == STAIR_z1) {score += 0x5000;} if (z2 == STAIR_z2) {score += 0x5000;} // // We like stairs opposite the 'opposite' wall. // if (z1 == z2 && st->opp_z1 == st->opp_z2) { doz = st->opp_z1 - z1; if (abs(doz) > 2) { if (WITHIN(x1, st->opp_x1, st->opp_x2)) {score += 0xbabe;} if (WITHIN(x2, st->opp_x1, st->opp_x2)) {score += 0xbabe;} } } if (x1 == x2 && st->opp_x1 == st->opp_x2) { dox = st->opp_x1 - x1; if (abs(dox) > 2) { if (WITHIN(z1, st->opp_z1, st->opp_z2)) {score += 0xbabe;} if (WITHIN(z2, st->opp_z1, st->opp_z2)) {score += 0xbabe;} } } if (score > best_score) { best_x1 = x1; best_z1 = z1; best_x2 = x2; best_z2 = z2; best_score = score; } } } } if (best_score >= 0) { ASSERT(WITHIN(STAIR_stair_upto, 1, STAIR_MAX_STAIRS - 2)); // // Put a staircase here and on the other floor. // ss = &STAIR_stair[STAIR_stair_upto++]; ss->flag = 0; ss->x1 = best_x1; ss->z1 = best_z1; ss->x2 = best_x2; ss->z2 = best_z2; if (go_up) {ss->flag |= STAIR_FLAG_UP; ss->up = j;} if (go_down) {ss->flag |= STAIR_FLAG_DOWN; ss->down = j;} STAIR_add_to_storey(i, STAIR_stair_upto - 1); // // The other floor. // ss = &STAIR_stair[STAIR_stair_upto++]; ss->flag = 0; ss->x1 = best_x1; ss->z1 = best_z1; ss->x2 = best_x2; ss->z2 = best_z2; // // These are swapped around for the other floor. // if (go_up) {ss->flag |= STAIR_FLAG_DOWN; ss->down = i;} if (go_down) {ss->flag |= STAIR_FLAG_UP; ss->up = j;} STAIR_add_to_storey(j, STAIR_stair_upto - 1); } else { // // We need some stairs, but there is nowhere to put // them! // TRACE("Oh no! Can't place stairs.\n"); } placed_stairs:; } else { // // Storeys i and j are more than one floor apart. // } } } } ID_Stair STAIR_id_stair[STAIR_MAX_PER_STOREY]; SLONG STAIR_get(SLONG handle, ID_Stair **stair, SLONG *num_stairs) { SLONG i; SLONG storey; STAIR_Storey *st; STAIR_Stair *ss; ID_Stair *is; for (i = 0; i < STAIR_storey_upto; i++) { st = &STAIR_storey[i]; if (st->handle == handle) { // // Found the storey. // goto found_storey_handle; } } // // Could not find a storey with the given handle. // return FALSE; found_storey_handle: *num_stairs = 0; for (i = 0; i < STAIR_MAX_PER_STOREY; i++) { if (st->stair[i] != NULL) { ASSERT(WITHIN(*num_stairs, 0, STAIR_MAX_PER_STOREY - 1)); ASSERT(WITHIN(st->stair[i], 1, STAIR_stair_upto - 1)); ss = &STAIR_stair [st->stair[i]]; is = &STAIR_id_stair[*num_stairs]; // // Add this stair to the array of ID_stairs... // is->x1 = ss->x1; is->z1 = ss->z1; is->x2 = ss->x2; is->z2 = ss->z2; if (ss->flag == STAIR_FLAG_UP) { ASSERT(WITHIN(ss->up, 0, STAIR_storey_upto - 1)); is->type = ID_STAIR_TYPE_BOTTOM; is->handle_up = STAIR_storey[ss->up].handle; } else if (ss->flag == STAIR_FLAG_DOWN) { ASSERT(WITHIN(ss->down, 0, STAIR_storey_upto - 1)); is->type = ID_STAIR_TYPE_TOP; is->handle_down = STAIR_storey[ss->down].handle; } else { ASSERT(ss->flag == (STAIR_FLAG_UP | STAIR_FLAG_DOWN)); ASSERT(WITHIN(ss->up, 0, STAIR_storey_upto - 1)); ASSERT(WITHIN(ss->down, 0, STAIR_storey_upto - 1)); is->type = ID_STAIR_TYPE_MIDDLE; is->handle_up = STAIR_storey[ss->up ].handle; is->handle_down = STAIR_storey[ss->down].handle; } // // Do not define the id... // is->id = 0; *num_stairs += 1; } } // // Return the array... // *stair = STAIR_id_stair; return TRUE; }