MuckyFoot-UrbanChaos/fallen/Source/ns.cpp
2017-05-20 11:14:17 +10:00

3921 lines
68 KiB
C++

//
// A new sewer system.
//
#ifndef TARGET_DC
#include "game.h"
#include "ns.h"
#include "heap.h"
#include "pap.h"
//
// Around the edges of the sewers there are curvey bits.
// This have type NS_HI_TYPE_CURVE. The type of curve
// is put into the water field of the square.
//
#define NS_HI_CURVE_XS 0 // Normal curves along corridors...
#define NS_HI_CURVE_XL 1
#define NS_HI_CURVE_ZS 2
#define NS_HI_CURVE_ZL 3
#define NS_HI_CURVE_ASS 4 // Acute angles on the inside of corners.
#define NS_HI_CURVE_ALS 5
#define NS_HI_CURVE_ASL 6
#define NS_HI_CURVE_ALL 7
#define NS_HI_CURVE_OSS 8 // Obtuse angles on the outside of corners.
#define NS_HI_CURVE_OLS 9
#define NS_HI_CURVE_OSL 10
#define NS_HI_CURVE_OLL 11
//
// The textures. The most common textures are already declared
// to speed things up.
//
#define NS_TEXTURE_FULL 0
#define NS_TEXTURE_HSTRIP1 1
#define NS_TEXTURE_HSTRIP2 2
#define NS_TEXTURE_HSTRIP3 3
#define NS_TEXTURE_HSTRIP4 4
#define NS_TEXTURE_HSTRIP5 5
#define NS_TEXTURE_HSTRIP6 6
#define NS_TEXTURE_HSTRIP7 7
#define NS_TEXTURE_HSTRIP8 8
#define NS_TEXTURE_HSTRIP9 9
#define NS_TEXTURE_HSTRIP10 10
#define NS_TEXTURE_CT1 11
#define NS_TEXTURE_CT2 12
#define NS_TEXTURE_CT3 13
#define NS_TEXTURE_CT4 14
#define NS_TEXTURE_CT5 15
#define NS_TEXTURE_CT6 16
#define NS_TEXTURE_CT7 17
#define NS_TEXTURE_CT8 18
#define NS_TEXTURE_CT9 19
#define NS_TEXTURE_CT10 20
#define NS_TEXTURE_CT11 21
#define NS_TEXTURE_CT12 22
#define NS_TEXTURE_CT13 23
#define NS_TEXTURE_CT14 24
#define NS_TEXTURE_CT15 25
#define NS_TEXTURE_CT16 26
#define NS_TEXTURE_EL1 27
#define NS_TEXTURE_EL2 28
#define NS_TEXTURE_ER1 29
#define NS_TEXTURE_ER2 30
#define NS_TEXTURE_NUMBER 31
NS_Texture NS_texture[NS_MAX_TEXTURES] =
{
{{0, 32, 0, 32}, { 0, 0, 32, 32}},
{{ 0, 32, 0, 32}, { 0, 0, 8, 8}},
{{ 0, 32, 0, 32}, { 0, 0, 12, 12}},
{{ 0, 32, 0, 32}, {12, 12, 32, 32}},
{{ 0, 32, 0, 24}, { 0, 0, 12, 12}},
{{ 0, 32, 8, 32}, { 0, 0, 12, 12}},
{{ 0, 24, 0, 12}, {12, 12, 32, 32}},
{{ 8, 32, 20, 32}, {12, 12, 32, 32}},
{{ 0, 0, 12, 0}, {12, 0, 12, 12}},
{{ 0, 8, 0, 32}, {12, 12, 32, 32}},
{{ 8, 0, 32, 0}, {12, 12, 32, 32}},
{{ 0, 16, 0, 16}, { 0, 0, 32, 32}},
{{16, 32, 16, 32}, { 0, 0, 32, 32}},
{{ 0, 32, 0, 32}, { 0, 0, 16, 16}},
{{ 0, 32, 0, 32}, {16, 16, 32, 32}},
{{ 0, 16, 0, 12}, { 0, 0, 16, 12}},
{{16, 32, 20, 32}, { 0, 0, 12, 16}},
{{ 0, 12, 0, 16}, {16, 20, 32, 32}},
{{20, 32, 16, 32}, {20, 16, 32, 32}},
{{ 0, 20, 0, 16}, { 0, 20, 32, 32}},
{{ 0, 32, 20, 32}, { 0, 0, 20, 16}},
{{ 0, 32, 0, 12}, { 0, 0, 16, 20}},
{{12, 32, 16, 32}, {20, 0, 32, 32}},
{{ 0, 16, 0, 20}, { 0, 0, 32, 12}},
{{20, 32, 0, 32}, {12, 16, 32, 32}},
{{ 0, 12, 0, 32}, {16, 12, 32, 32}},
{{16, 32, 12, 32}, { 0, 0, 12, 32}},
{{16, 0, 24, 0}, {32, 32, 12, 0}},
{{32, 24, 32, 0}, { 8, 12, 0, 0}},
{{32, 16, 32, 8}, {32, 32, 0, 12}},
{{ 8, 0, 32, 0}, {12, 8, 0, 0}},
};
SLONG NS_texture_upto = NS_TEXTURE_NUMBER;
//
// The pages.
//
NS_Page NS_page[NS_PAGE_NUMBER] =
#ifdef PSX
{
1,2,3,4,5
};
//
// What are the offset into the texture page of these textures?
//
#else
{
149, // Rock
187, // Sewer
189, // Stone
187, // Sewer walls
37 // Grating
};
#endif
//
// The maps.
//
NS_Lo NS_lo[PAP_SIZE_LO][PAP_SIZE_LO];
NS_Hi NS_hi[PAP_SIZE_HI][PAP_SIZE_HI];
//
// The cache elemnts.
//
NS_Cache NS_cache[NS_MAX_CACHES];
UBYTE NS_cache_free;
//
// The water fall.
//
NS_Fall NS_fall[NS_MAX_FALLS];
UBYTE NS_fall_free;
//
// The things.
//
NS_St NS_st[NS_MAX_STS];
UBYTE NS_st_free;
//
// The normals.
//
#define NS_NORM_XL 0
#define NS_NORM_XS 1
#define NS_NORM_ZL 2
#define NS_NORM_ZS 3
#define NS_NORM_YL 4
#define NS_NORM_DUNNO 5
#define NS_NORM_BLACK 6
#define NS_NORM_GREY 7
void NS_init()
{
SLONG i;
SLONG x;
SLONG z;
NS_Hi *nh;
memset((UBYTE*)NS_hi, 0, sizeof(NS_hi));
memset((UBYTE*)NS_lo, 0, sizeof(NS_lo));
//
// Rock everywhere.
//
for (x = 0; x < PAP_SIZE_HI; x++)
for (z = 0; z < PAP_SIZE_HI; z++)
{
nh = &NS_hi[x][z];
nh->packed = NS_HI_TYPE_ROCK;
nh->bot = 0x100 - 8 * 2;
}
//
// Initialise the things.
//
NS_st_free = 1;
for (i = 1; i < NS_MAX_STS - 1; i++)
{
NS_st[i].type = NS_ST_TYPE_UNUSED;
NS_st[i].next = i + 1;
}
NS_st[NS_MAX_STS - 1].next = NULL;
}
//
// Calculate the top heights of the rock
//
void NS_precalculate()
{
SLONG i;
SLONG j;
SLONG x;
SLONG z;
SLONG top;
SLONG num;
SLONG used;
SLONG above;
SLONG nx;
SLONG nz;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG px;
SLONG pz;
SLONG sx;
SLONG sz;
SLONG px1;
SLONG pz1;
SLONG px2;
SLONG pz2;
ULONG flag;
SLONG curve;
NS_Hi *nh;
NS_Hi *nh2;
//
// Mark all top bits as unused.
//
for (x = 0; x < PAP_SIZE_HI; x++)
for (z = 0; z < PAP_SIZE_HI; z++)
{
nh = &NS_hi[x][z];
nh->packed &= ~NS_HI_FLAG_TOPUSED;
nh->packed &= ~NS_HI_FLAG_LOCKTOP;
//
// Make sure 'bot' lies on a mapsquare boundary.
//
nh->bot &= 0xf8;
//
// No rock squares can have water.
//
if (NS_HI_TYPE(nh) == NS_HI_TYPE_ROCK)
{
nh->water = 0;
}
//
// Grates have water beneath them.
//
if (nh->packed & NS_HI_FLAG_GRATE)
{
ASSERT(nh->bot >= 16);
nh->water = nh->bot - 8;
}
}
for (x = 1; x < PAP_SIZE_HI - 1; x++)
for (z = 1; z < PAP_SIZE_HI - 1; z++)
{
nh = &NS_hi[x][z];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_ROCK)
{
//
// Go through all the points used with this square and
// set the TOPUSED bit.
//
for (i = 0; i < 4; i++)
{
px = x + (i & 1);
pz = z + (i >> 1);
ASSERT(WITHIN(px, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_HI - 1));
nh2 = &NS_hi[px][pz];
nh2->packed |= NS_HI_FLAG_TOPUSED;
}
}
}
//
// Make sure no walls are too high or too low.
//
for (x = 1; x < PAP_SIZE_HI - 1; x++)
for (z = 1; z < PAP_SIZE_HI - 1; z++)
{
nh = &NS_hi[x][z];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_STONE)
{
for (dx = 0; dx <= 1; dx++)
for (dz = 0; dz <= 1; dz++)
{
nx = x + dx;
nz = z + dz;
nh2 = &NS_hi[nx][nz];
if (nh2->packed & NS_HI_FLAG_TOPUSED)
{
dy = nh2->top;
dy -= nh->bot;
if (dy > 32)
{
dy = 30 + (rand() & 0x3);
nh2->packed |= NS_HI_FLAG_LOCKTOP;
}
if (dy < 8)
{
dy = 8;
nh2->packed |= NS_HI_FLAG_LOCKTOP;
}
top = nh->bot;
top += dy;
if (top > 255)
{
top = 255;
}
nh2->top = top;
}
}
}
}
//
// Find all points that lie on the edges of sewers and
// set their top height to be at the edge of the sewer.
// Set their locked bit to make sure they don't move down.
//
for (x = 1; x < PAP_SIZE_HI - 1; x++)
for (z = 1; z < PAP_SIZE_HI - 1; z++)
{
nh = &NS_hi[x][z];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_SEWER)
{
top = nh->bot + 8;
if (top > 255) {top = 255;}
//
// Look for neigbouring squares that aren't sewers.
//
const struct
{
SBYTE dsx;
SBYTE dsz;
SBYTE dpx1;
SBYTE dpz1;
SBYTE dpx2;
SBYTE dpz2;
} neighbour[4] =
{
{-1,0, 0,0, 0,1},
{+1,0, 1,0, 1,1},
{0,-1, 0,0, 1,0},
{0,+1, 0,1, 1,1}
};
for (i = 0; i < 4; i++)
{
sx = x + neighbour[i].dsx;
sz = z + neighbour[i].dsz;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh2 = &NS_hi[sx][sz];
if (NS_HI_TYPE(nh2) != NS_HI_TYPE_SEWER)
{
//
// Found a neighbouring square that ain't a sewer.
// Set the points shared with the square.
//
px1 = x + neighbour[i].dpx1;
pz1 = z + neighbour[i].dpz1;
px2 = x + neighbour[i].dpx2;
pz2 = z + neighbour[i].dpz2;
ASSERT(WITHIN(px1, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(pz1, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(px2, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(pz2, 0, PAP_SIZE_HI - 1));
NS_hi[px1][pz1].packed |= NS_HI_FLAG_LOCKTOP;
NS_hi[px2][pz2].packed |= NS_HI_FLAG_LOCKTOP;
NS_hi[px1][pz1].top = top;
NS_hi[px2][pz2].top = top;
}
}
}
}
//
// Even out the top map.
//
#define NS_EVEN_OUT_INNER 3
#define NS_EVEN_OUT_OUTER 5
const static SLONG jitter[8] =
{
-2,
-1,
-1,
0,
0,
+1,
+1,
+2
};
for (i = 0; i < NS_EVEN_OUT_OUTER; i++)
{
for (x = 1; x < PAP_SIZE_HI - 1; x++)
for (z = 1; z < PAP_SIZE_HI - 1; z++)
{
nh = &NS_hi[x][z];
if ( (nh->packed & NS_HI_FLAG_TOPUSED) &&
!(nh->packed & NS_HI_FLAG_LOCKTOP))
{
//
// Move this point to the average of the surrounding points
// and yourself.
//
top = nh->top;
num = 1;
for (j = 0; j < NS_EVEN_OUT_INNER; j++)
{
dx = jitter[rand() & 0x7];
dz = jitter[rand() & 0x7];
px = x + dx;
pz = z + dz;
if (WITHIN(px, 1, PAP_SIZE_HI - 1) &&
WITHIN(pz, 1, PAP_SIZE_HI - 1))
{
nh2 = &NS_hi[px][pz];
if (nh2->packed & NS_HI_FLAG_TOPUSED)
{
top += nh2->top;
num += 1;
}
}
}
nh->top = top / num;
}
}
}
/*
//
// Randomise everything a bit.
//
for (x = 1; x < PAP_SIZE_HI - 1; x++)
for (z = 1; z < PAP_SIZE_HI - 1; z++)
{
nh = &NS_hi[x][z];
if (!(nh->packed & NS_HI_FLAG_LOCKTOP) &&
(nh->packed & NS_HI_FLAG_TOPUSED))
{
top = nh->top;
top += rand() & 0x3;
top -= 2;
if (top > 255)
{
top = 255;
}
nh->top = top;
}
}
*/
//
// Make all rock on the edge of sewers a curvey bit.
//
for (x = 1; x < PAP_SIZE_HI - 1; x++)
for (z = 1; z < PAP_SIZE_HI - 1; z++)
{
nh = &NS_hi[x][z];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_ROCK)
{
#define FLAG_XS (1 << 0)
#define FLAG_XL (1 << 1)
#define FLAG_ZS (1 << 2)
#define FLAG_ZL (1 << 3)
flag = 0;
if (NS_HI_TYPE(&NS_hi[x + 1][z]) == NS_HI_TYPE_SEWER) {flag |= FLAG_XS;}
if (NS_HI_TYPE(&NS_hi[x - 1][z]) == NS_HI_TYPE_SEWER) {flag |= FLAG_XL;}
if (NS_HI_TYPE(&NS_hi[x][z + 1]) == NS_HI_TYPE_SEWER) {flag |= FLAG_ZS;}
if (NS_HI_TYPE(&NS_hi[x][z - 1]) == NS_HI_TYPE_SEWER) {flag |= FLAG_ZL;}
curve = -1;
switch(flag)
{
case FLAG_XS: curve = NS_HI_CURVE_XS; break;
case FLAG_XL: curve = NS_HI_CURVE_XL; break;
case FLAG_ZS: curve = NS_HI_CURVE_ZS; break;
case FLAG_ZL: curve = NS_HI_CURVE_ZL; break;
case FLAG_XS | FLAG_ZS: curve = NS_HI_CURVE_ASS; break;
case FLAG_XL | FLAG_ZS: curve = NS_HI_CURVE_ALS; break;
case FLAG_XS | FLAG_ZL: curve = NS_HI_CURVE_ASL; break;
case FLAG_XL | FLAG_ZL: curve = NS_HI_CURVE_ALL; break;
}
if (curve == -1)
{
//
// Do an extra check for obtuse-angle curves.
//
if (NS_HI_TYPE(&NS_hi[x + 1][z + 1]) == NS_HI_TYPE_SEWER) {curve = NS_HI_CURVE_OSS;}
if (NS_HI_TYPE(&NS_hi[x - 1][z + 1]) == NS_HI_TYPE_SEWER) {curve = NS_HI_CURVE_OLS;}
if (NS_HI_TYPE(&NS_hi[x + 1][z - 1]) == NS_HI_TYPE_SEWER) {curve = NS_HI_CURVE_OSL;}
if (NS_HI_TYPE(&NS_hi[x - 1][z - 1]) == NS_HI_TYPE_SEWER) {curve = NS_HI_CURVE_OLL;}
}
if (curve != -1)
{
//
// Mark this square as being curvey.
//
NS_HI_TYPE_SET(nh, NS_HI_TYPE_CURVE);
nh->water = curve;
//
// The bot height of this square should be set to the
// bot height of the sewer it is adjacent to.
//
for (dx = -1; dx <= 1; dx++)
for (dz = -1; dz <= 1; dz++)
{
nh2 = &NS_hi[x + dx][z + dz];
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_SEWER)
{
nh->bot = nh2->bot;
goto found_adjacent_sewer_square;
}
}
//
// Argh! The universe has gone wrong.
//
ASSERT(0);
found_adjacent_sewer_square:;
}
}
}
}
void NS_cache_init()
{
SLONG i;
SLONG x;
SLONG z;
//
// We keep cached points and faces on the heap.
//
HEAP_init();
//
// Build the free list of cache entries.
//
NS_cache_free = 1;
for (i = 1; i < NS_MAX_CACHES - 1; i++)
{
NS_cache[i].used = FALSE;
NS_cache[i].next = i + 1;
}
NS_cache[NS_MAX_CACHES - 1].next = NULL;
//
// Clear the cache field in the map.
//
for (x = 0; x < PAP_SIZE_LO; x++)
for (z = 0; z < PAP_SIZE_LO; z++)
{
NS_lo[x][z].cache = NULL;
}
//
// The waterfalls.
//
NS_fall_free = 1;
for (i = 1; i < NS_MAX_FALLS - 1; i++)
{
NS_fall[i].next = i + 1;
}
NS_fall[NS_MAX_FALLS - 1].next = NULL;
}
//
// Adding points and faces to the scratch buffer.
//
#define NS_MAX_SCRATCH_POINTS ((HEAP_PAD_SIZE / 2) / sizeof(NS_Point))
#define NS_MAX_SCRATCH_FACES ((HEAP_PAD_SIZE / 2) / sizeof(NS_Face))
NS_Point *NS_scratch_point = (NS_Point *) (&HEAP_pad[0]);
NS_Face *NS_scratch_face = (NS_Face *) (&HEAP_pad[HEAP_PAD_SIZE / 2]);
SLONG NS_scratch_point_upto = 0;
SLONG NS_scratch_face_upto = 0;
//
// The coordinates of the bottom-left corner of the lo-res mapsquare
// whose points we are adding to the scratch buffers.
//
SLONG NS_scratch_origin_x;
SLONG NS_scratch_origin_z;
//
// When we add a point it is lit from this light.
//
typedef struct
{
SLONG x;
SLONG y;
SLONG z;
} NS_Slight;
#define NS_MAX_SLIGHTS 9
NS_Slight NS_slight[NS_MAX_SLIGHTS];
SLONG NS_slight_upto;
void NS_add_point(
SLONG x,
SLONG y,
SLONG z, // y is in the NS coordinate system. Eighth map-square from 32 blocks underground.
SLONG norm)
{
SLONG i;
SLONG px;
SLONG py;
SLONG pz;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG bright;
SLONG light;
SLONG dprod;
NS_Slight *nss;
ASSERT(WITHIN(NS_scratch_point_upto, 0, NS_MAX_SCRATCH_POINTS - 1));
px = x - NS_scratch_origin_x >> 3;
pz = z - NS_scratch_origin_z >> 3;
py = y;
ASSERT(WITHIN(px, 0, 128));
ASSERT(WITHIN(pz, 0, 128));
ASSERT(WITHIN(py, 0, 255));
if (norm == NS_NORM_BLACK) {bright = 0;}
else if (norm == NS_NORM_GREY) {bright = 32;}
else
{
bright = 192 - (norm << 3);
for (i = 0; i < NS_slight_upto; i++)
{
nss = &NS_slight[i];
dx = nss->x - px;
dy = nss->y - py << 2;
dz = nss->z - pz;
dist = QDIST3(abs(dx),abs(dy),abs(dz)) + 1;
switch(norm)
{
case NS_NORM_XL: if (dx <= 0) {continue;} else {dprod = dx * 256 / dist;} break;
case NS_NORM_XS: if (dx >= 0) {continue;} else {dprod = -dx * 256 / dist;} break;
case NS_NORM_ZL: if (dz <= 0) {continue;} else {dprod = dz * 256 / dist;} break;
case NS_NORM_ZS: if (dz >= 0) {continue;} else {dprod = -dz * 256 / dist;} break;
case NS_NORM_YL: if (dy <= 0) {continue;} else {dprod = dy * 256 / dist;} break;
case NS_NORM_DUNNO: dprod = 200; break;
default:
ASSERT(0);
break;
}
ASSERT(dprod >= 0);
light = 256 - (dist << 1);
if (light > 0)
{
light = light * dprod >> 8;
bright += light;
}
}
SATURATE(bright, 50, 255);
}
NS_scratch_point[NS_scratch_point_upto].x = px;
NS_scratch_point[NS_scratch_point_upto].y = py;
NS_scratch_point[NS_scratch_point_upto].z = pz;
NS_scratch_point[NS_scratch_point_upto].bright = bright;
NS_scratch_point_upto += 1;
}
void NS_add_face(
SLONG p[4],
UBYTE page,
UBYTE texture)
{
ASSERT(WITHIN(NS_scratch_face_upto, 0, NS_MAX_SCRATCH_FACES - 1));
ASSERT(WITHIN(p[0], 0, NS_scratch_point_upto - 1));
ASSERT(WITHIN(p[1], 0, NS_scratch_point_upto - 1));
ASSERT(WITHIN(p[2], 0, NS_scratch_point_upto - 1));
ASSERT(WITHIN(p[3], 0, NS_scratch_point_upto - 1));
ASSERT(WITHIN(page, 0, NS_PAGE_NUMBER - 1));
ASSERT(WITHIN(texture, 0, NS_MAX_TEXTURES - 1));
NS_scratch_face[NS_scratch_face_upto].p[0] = p[0];
NS_scratch_face[NS_scratch_face_upto].p[1] = p[1];
NS_scratch_face[NS_scratch_face_upto].p[2] = p[2];
NS_scratch_face[NS_scratch_face_upto].p[3] = p[3];
NS_scratch_face[NS_scratch_face_upto].page = page;
NS_scratch_face[NS_scratch_face_upto].texture = texture;
NS_scratch_face_upto += 1;
}
//
// Creates the top and bottom squares into the scratch pad.
//
void NS_cache_create_floors(UBYTE mx, UBYTE mz)
{
SLONG i;
SLONG j;
SLONG x;
SLONG z;
SLONG px;
SLONG py;
SLONG pz;
SLONG bx;
SLONG bz;
SLONG sx;
SLONG sz;
SLONG page;
SLONG p[4];
NS_Hi *ns;
//
// The top points.
//
UBYTE pindex[5][5];
#ifndef NDEBUG
memset((UBYTE*)pindex, 255, sizeof(pindex));
#endif
for (x = 0; x <= 4; x++)
for (z = 0; z <= 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
ns = &NS_hi[sx][sz];
if (ns->packed & NS_HI_FLAG_TOPUSED)
{
px = sx << 8;
pz = sz << 8;
py = ns->top;
pindex[x][z] = NS_scratch_point_upto;
NS_add_point(
px,
py,
pz,
NS_NORM_YL);
}
}
//
// The top squares.
//
for (x = 0; x < 4; x++)
for (z = 0; z < 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
ns = &NS_hi[sx][sz];
if (NS_HI_TYPE(ns) == NS_HI_TYPE_ROCK)
{
p[0] = pindex[x + 0][z + 0];
p[1] = pindex[x + 1][z + 0];
p[2] = pindex[x + 0][z + 1];
p[3] = pindex[x + 1][z + 1];
ASSERT(p[0] < 25);
ASSERT(p[1] < 25);
ASSERT(p[2] < 25);
ASSERT(p[3] < 25);
NS_add_face(
p,
NS_PAGE_ROCK,
NS_TEXTURE_FULL);
}
}
//
// Sort the bottom squares in order of height.
//
typedef struct
{
UBYTE x;
UBYTE z;
UBYTE bot; // The bot height of square (x,z) (optimisation only)
} Bsquare;
#define MAX_BSQUARES 16
Bsquare bsquare[MAX_BSQUARES];
SLONG bsquare_upto = 0;
SLONG insert;
for (x = 0; x < 4; x++)
for (z = 0; z < 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
ns = &NS_hi[sx][sz];
if (NS_HI_TYPE(ns) != NS_HI_TYPE_ROCK &&
NS_HI_TYPE(ns) != NS_HI_TYPE_NOTHING &&
NS_HI_TYPE(ns) != NS_HI_TYPE_CURVE)
{
if ((ns->water && !(ns->packed & NS_HI_FLAG_GRATE)) || ns->bot == 0)
{
//
// Water in a sewer is not transparent, so there
// is no need to draw the ground underneath it- except under a grating.
//
// if (bot == 0) then the ground is at -INFINITY...
// so we can't see it!
//
}
else
{
//
// Add this square to the array sorted in order of depth.
//
insert = bsquare_upto;
while(1)
{
if (insert == 0)
{
//
// No square left to compare against.
//
bsquare[insert].x = sx;
bsquare[insert].z = sz;
bsquare[insert].bot = ns->bot;
break;
}
ASSERT(WITHIN(insert - 1, 0, MAX_BSQUARES - 1));
ASSERT(WITHIN(insert - 0, 0, MAX_BSQUARES - 1));
if (ns->bot >= bsquare[insert - 1].bot)
{
//
// This is where to insert the square.
//
bsquare[insert].x = sx;
bsquare[insert].z = sz;
bsquare[insert].bot = ns->bot;
break;
}
else
{
bsquare[insert] = bsquare[insert - 1];
}
insert -= 1;
}
bsquare_upto += 1;
}
}
}
//
// Mark all points as undefined.
//
memset((UBYTE*)pindex, 255, sizeof(pindex));
//
// Go through each of the squares from the bottom to the top.
//
for (i = 0; i < bsquare_upto; i++)
{
sx = bsquare[i].x;
sz = bsquare[i].z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
ns = &NS_hi[sx][sz];
bx = sx - (mx << 2);
bz = sz - (mz << 2);
ASSERT(WITHIN(bx, 0, 3));
ASSERT(WITHIN(bz, 0, 3));
//
// Create the points for this square.
//
for (j = 0; j < 4; j++)
{
x = bx + (j & 1);
z = bz + (j >> 1);
if (pindex[x][z] != 255)
{
//
// We already have a point at this position. It is at the
// correct height?
//
ASSERT(WITHIN(pindex[x][z], 0, NS_scratch_point_upto - 1));
if (NS_scratch_point[pindex[x][z]].y == ns->bot)
{
//
// Use this point.
//
p[j] = pindex[x][z];
goto reusing_an_old_point;
}
}
//
// We have to create a new point here.
//
pindex[x][z] = NS_scratch_point_upto;
p[j] = NS_scratch_point_upto;
px = (x << 8) + (mx << PAP_SHIFT_LO);
pz = (z << 8) + (mz << PAP_SHIFT_LO);
py = ns->bot;
NS_add_point(px, py, pz, NS_NORM_YL);
reusing_an_old_point:;
}
//
// Create the face.
//
if (ns->packed & NS_HI_FLAG_GRATE)
{
page = NS_PAGE_GRATE;
}
else
{
page = NS_PAGE_STONE;
}
NS_add_face(p, page, NS_TEXTURE_FULL);
}
}
//
// Used by create_wallstrip() to add points. If it finds the point in the
// search region, then it returns the index of that point, otherwise it
// creates it.
//
SLONG NS_search_start;
SLONG NS_search_end; // Exclusive
SLONG NS_create_wallstrip_point(
SLONG x,
SLONG y,
SLONG z,
SLONG norm)
{
SLONG i;
SLONG px;
SLONG py;
SLONG pz;
SLONG ans;
px = (x - NS_scratch_origin_x) >> 3;
pz = (z - NS_scratch_origin_z) >> 3;
py = y;
ASSERT(WITHIN(px, 0, 128));
ASSERT(WITHIN(pz, 0, 128));
ASSERT(WITHIN(py, 0, 255));
for (i = NS_search_start; i < NS_search_end; i++)
{
ASSERT(WITHIN(i, 0, NS_scratch_point_upto - 1));
if (NS_scratch_point[i].x == px &&
NS_scratch_point[i].y == py &&
NS_scratch_point[i].z == pz)
{
return i;
}
}
//
// We must create the point.
//
ans = NS_scratch_point_upto;
NS_add_point(x, y, z, norm);
return ans;
}
SLONG NS_create_wallstrip_point(
SLONG x,
SLONG y,
SLONG z)
{
return NS_create_wallstrip_point(x, y, z, NS_NORM_DUNNO);
}
//
// Creates a strip of wall which must start at a mapsquare boundary.
// 'shared' is a hint. The function looks from shared to the end of
// the scratch_point array for points that match ones it wants to create.
//
void NS_cache_create_wallstrip(
SLONG px1, SLONG pz1,
SLONG px2, SLONG pz2,
SLONG bot, // On a mapsquare boundary.
SLONG ty1, SLONG ty2,
SLONG shared,
SLONG norm)
{
SLONG last1;
SLONG last2;
SLONG now1;
SLONG now2;
SLONG py1;
SLONG py2;
SLONG p[4];
SLONG darken_bottom;
SLONG usenorm;
//
// Make sure bot is on a mapsquare boundary.
//
ASSERT((bot & 0x7) == 0);
if (bot == 0)
{
bot = MIN(ty1,ty2);
bot -= 24;
bot &= ~7;
darken_bottom = TRUE;
}
else
{
darken_bottom = FALSE;
}
//
// The inclusive region searched to avoid creating identical points.
//
NS_search_start = shared;
NS_search_end = NS_scratch_point_upto;
//
// Create the two bottom points.
//
last1 = NS_create_wallstrip_point(px1, bot, pz1, (darken_bottom) ? NS_NORM_BLACK : norm);
last2 = NS_create_wallstrip_point(px2, bot, pz2, (darken_bottom) ? NS_NORM_BLACK : norm);
py1 = bot + 8;
py2 = bot + 8;
while(1)
{
if (py1 >= ty1 ||
py2 >= ty2)
{
py1 = ty1;
py2 = ty2;
}
//
// Create two new points.
//
if (darken_bottom)
{
usenorm = NS_NORM_GREY;
darken_bottom = FALSE;
}
else
{
usenorm = norm;
}
now1 = NS_create_wallstrip_point(px1, py1, pz1, usenorm);
now2 = NS_create_wallstrip_point(px2, py2, pz2, usenorm);
//
// Create the face quad.
//
p[0] = last1;
p[1] = last2;
p[2] = now1;
p[3] = now2;
NS_add_face(p, NS_PAGE_STONE, NS_TEXTURE_FULL);
//
// Reached the end of the strip.
//
if (py1 >= ty1 ||
py2 >= ty2)
{
return;
}
py1 += 8;
py2 += 8;
if (py1 > 255) {py1 = 255;}
if (py2 > 255) {py2 = 255;}
last1 = now1;
last2 = now2;
}
}
//
// The extra bits of wall at the top of a sewer.
//
void NS_cache_create_extra_bit_left(
SLONG px1, SLONG pz1,
SLONG px2, SLONG pz2,
SLONG bottom,
SLONG ty1, SLONG ty2,
SLONG norm)
{
SLONG dx = px2 - px1 >> 8;
SLONG dz = pz2 - pz1 >> 8;
SLONG pindex[6];
SLONG p[4];
//
// Create all the points.
//
pindex[0] = NS_create_wallstrip_point(px1, bottom, pz1, norm);
pindex[1] = NS_create_wallstrip_point(px1, ty1, pz1, norm);
pindex[2] = NS_create_wallstrip_point(px1 + dx * 128, bottom + 8, pz1 + dz * 128, norm);
pindex[3] = NS_create_wallstrip_point(px1 + dx * 192, bottom + 3, pz1 + dz * 192, norm);
pindex[4] = NS_create_wallstrip_point(px1 + dx * 256, bottom + 2, pz1 + dz * 256, norm);
pindex[5] = NS_create_wallstrip_point(px1 + dx * 256, bottom, pz1 + dz * 256, norm);
//
// Create the two quads.
//
p[0] = pindex[2];
p[1] = pindex[1];
p[2] = pindex[3];
p[3] = pindex[0];
NS_add_face(p, NS_PAGE_STONE, NS_TEXTURE_EL1);
p[0] = pindex[4];
p[1] = pindex[3];
p[2] = pindex[5];
p[3] = pindex[0];
NS_add_face(p, NS_PAGE_STONE, NS_TEXTURE_EL2);
}
void NS_cache_create_extra_bit_right(
SLONG px1, SLONG pz1,
SLONG px2, SLONG pz2,
SLONG bottom,
SLONG ty1, SLONG ty2,
SLONG norm)
{
SLONG dx = px2 - px1 >> 8;
SLONG dz = pz2 - pz1 >> 8;
SLONG pindex[6];
SLONG p[4];
//
// Create all the points.
//
pindex[0] = NS_create_wallstrip_point(px2, bottom, pz2, norm);
pindex[1] = NS_create_wallstrip_point(px2, ty2, pz2, norm);
pindex[2] = NS_create_wallstrip_point(px2 - dx * 128, bottom + 8, pz2 - dz * 128, norm);
pindex[3] = NS_create_wallstrip_point(px2 - dx * 192, bottom + 3, pz2 - dz * 192, norm);
pindex[4] = NS_create_wallstrip_point(px2 - dx * 256, bottom + 2, pz2 - dz * 256, norm);
pindex[5] = NS_create_wallstrip_point(px2 - dx * 256, bottom, pz2 - dz * 256, norm);
//
// Create the two quads.
//
p[0] = pindex[1];
p[1] = pindex[2];
p[2] = pindex[0];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_STONE, NS_TEXTURE_ER1);
p[0] = pindex[3];
p[1] = pindex[4];
p[2] = pindex[0];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_STONE, NS_TEXTURE_ER2);
}
//
// Creates all the vertical walls.
//
void NS_cache_create_walls(UBYTE mx, UBYTE mz)
{
SLONG x;
SLONG z;
SLONG sx;
SLONG sz;
SLONG px1, pz1;
SLONG px2, pz2;
SLONG ty1;
SLONG ty2;
SLONG bot;
SLONG shared_last;
SLONG shared_now;
NS_Hi *nh;
NS_Hi *nh2;
//
// Walls parallel to the z-axis first.
//
for (x = 0; x < 4; x++)
{
//
// The strip from x to (x - 1)
//
shared_last = NS_scratch_point_upto - 1;
if (shared_last < 0)
{
shared_last = 0;
}
for (z = 0; z < 4; z++)
{
shared_now = NS_scratch_point_upto - 1;
if (shared_now < 0)
{
shared_now = 0;
}
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 1, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 1, PAP_SIZE_HI - 1));
nh = &NS_hi[sx ][sz];
nh2 = &NS_hi[sx - 1][sz];
if (NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK &&
NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE)
{
px1 = sx << 8;
pz1 = sz << 8;
px2 = sx << 8;
pz2 = sz + 1 << 8;
bot = nh->bot;
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_ROCK)
{
ty1 = NS_hi[sx][sz + 0].top;
ty2 = NS_hi[sx][sz + 1].top;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_XL);
}
else
{
if (nh2->bot > nh->bot)
{
ty1 = nh2->bot;
ty2 = nh2->bot;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_XL);
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_CURVE)
{
//
// Create the extra bits at the side of the sewer.
//
ty1 = NS_hi[sx][sz + 0].top;
ty2 = NS_hi[sx][sz + 1].top;
if (NS_HI_TYPE(&NS_hi[sx - 1][sz - 1]) == NS_HI_TYPE_ROCK)
{
NS_cache_create_extra_bit_left(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_XL);
}
else
{
NS_cache_create_extra_bit_right(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_XL);
}
}
}
}
}
shared_last = shared_now;
}
//
// The strip from x to (x + 1)
//
shared_last = NS_scratch_point_upto - 1;
if (shared_last < 0)
{
shared_last = 0;
}
for (z = 0; z < 4; z++)
{
shared_now = NS_scratch_point_upto - 1;
if (shared_now < 0)
{
shared_now = 0;
}
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 1, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 1, PAP_SIZE_HI - 1));
nh = &NS_hi[sx ][sz];
nh2 = &NS_hi[sx + 1][sz];
if (NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK &&
NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE)
{
px1 = sx + 1 << 8;
pz1 = sz + 1 << 8;
px2 = sx + 1 << 8;
pz2 = sz << 8;
bot = nh->bot;
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_ROCK)
{
ty1 = NS_hi[sx + 1][sz + 1].top;
ty2 = NS_hi[sx + 1][sz + 0].top;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_XS);
}
else
{
if (nh2->bot > nh->bot)
{
ty1 = nh2->bot;
ty2 = nh2->bot;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_XS);
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_CURVE)
{
//
// Create the extra bits at the side of the sewer.
//
ty1 = NS_hi[sx + 1][sz + 1].top;
ty2 = NS_hi[sx + 1][sz + 0].top;
if (NS_HI_TYPE(&NS_hi[sx + 1][sz + 1]) == NS_HI_TYPE_ROCK)
{
NS_cache_create_extra_bit_left(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_XS);
}
else
{
NS_cache_create_extra_bit_right(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_XS);
}
}
}
}
}
shared_last = shared_now;
}
}
//
// Walls parallel to the x-axis now.
//
for (z = 0; z < 4; z++)
{
//
// The strip from z to (z - 1)
//
shared_last = NS_scratch_point_upto - 1;
if (shared_last < 0)
{
shared_last = 0;
}
for (x = 0; x < 4; x++)
{
shared_now = NS_scratch_point_upto - 1;
if (shared_now < 0)
{
shared_now = 0;
}
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 1, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 1, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz ];
nh2 = &NS_hi[sx][sz - 1];
if (NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK &&
NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE)
{
px1 = sx + 1 << 8;
pz1 = sz << 8;
px2 = sx << 8;
pz2 = sz << 8;
bot = nh->bot;
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_ROCK)
{
ty1 = NS_hi[sx + 1][sz].top;
ty2 = NS_hi[sx + 0][sz].top;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_ZL);
}
else
{
if (nh2->bot > nh->bot)
{
ty1 = nh2->bot;
ty2 = nh2->bot;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_ZL);
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_CURVE)
{
//
// Create the extra bits at the side of the sewer.
//
ty1 = NS_hi[sx + 1][sz].top;
ty2 = NS_hi[sx + 0][sz].top;
if (NS_HI_TYPE(&NS_hi[sx + 1][sz - 1]) == NS_HI_TYPE_ROCK)
{
NS_cache_create_extra_bit_left(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_ZL);
}
else
{
NS_cache_create_extra_bit_right(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_ZL);
}
}
}
}
}
shared_last = shared_now;
}
//
// The strip from z to (z + 1)
//
shared_last = NS_scratch_point_upto - 1;
if (shared_last < 0)
{
shared_last = 0;
}
for (x = 0; x < 4; x++)
{
shared_now = NS_scratch_point_upto - 1;
if (shared_now < 0)
{
shared_now = 0;
}
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 1, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 1, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz ];
nh2 = &NS_hi[sx][sz + 1];
if (NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK &&
NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE)
{
px1 = sx << 8;
pz1 = sz + 1 << 8;
px2 = sx + 1 << 8;
pz2 = sz + 1 << 8;
bot = nh->bot;
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_ROCK)
{
ty1 = NS_hi[sx + 0][sz + 1].top;
ty2 = NS_hi[sx + 1][sz + 1].top;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_ZS);
}
else
{
if (nh2->bot > nh->bot)
{
ty1 = nh2->bot;
ty2 = nh2->bot;
NS_cache_create_wallstrip(
px1, pz1,
px2, pz2,
bot,
ty1, ty2,
shared_last,
NS_NORM_ZS);
if (NS_HI_TYPE(nh2) == NS_HI_TYPE_CURVE)
{
//
// Create the extra bits at the side of the sewer.
//
ty1 = NS_hi[sx + 0][sz + 1].top;
ty2 = NS_hi[sx + 1][sz + 1].top;
if (NS_HI_TYPE(&NS_hi[sx - 1][sz + 1]) == NS_HI_TYPE_ROCK)
{
NS_cache_create_extra_bit_left(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_ZS);
}
else
{
NS_cache_create_extra_bit_right(
px1, pz1,
px2, pz2,
nh2->bot,
ty1, ty2,
NS_NORM_ZS);
}
}
}
}
}
shared_last = shared_now;
}
}
}
//
// Creates a segment of curved sewer wall.
//
void NS_cache_create_curve_sewer(
SLONG sx,
SLONG sz)
{
SLONG px1;
SLONG pz1;
SLONG px2;
SLONG pz2;
SLONG dx;
SLONG dz;
SLONG dx1;
SLONG dz1;
SLONG dx2;
SLONG dz2;
SLONG px;
SLONG py;
SLONG pz;
SLONG p[4];
SLONG curve;
NS_Hi *nh;
UBYTE pindex[16];
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz];
//
// What type of sewer wall curve?
//
curve = nh->water;
if (curve < 4)
{
//
// Normal flat types. Set the paramters we use to create
// the flat curve at different places and rotations.
//
switch(curve)
{
case NS_HI_CURVE_XS:
px1 = sx + 1 << 8;
pz1 = sz + 0 << 8;
px2 = sx + 1 << 8;
pz2 = sz + 1 << 8;
dx = -256;
dz = 0;
break;
case NS_HI_CURVE_XL:
px1 = sx + 0 << 8;
pz1 = sz + 1 << 8;
px2 = sx + 0 << 8;
pz2 = sz + 0 << 8;
dx = +256;
dz = 0;
break;
case NS_HI_CURVE_ZS:
px1 = sx + 1 << 8;
pz1 = sz + 1 << 8;
px2 = sx + 0 << 8;
pz2 = sz + 1 << 8;
dx = 0;
dz = -256;
break;
case NS_HI_CURVE_ZL:
px1 = sx + 0 << 8;
pz1 = sz + 0 << 8;
px2 = sx + 1 << 8;
pz2 = sz + 0 << 8;
dx = 0;
dz = +256;
break;
default:
ASSERT(0);
break;
}
//
// Create the points and faces.
//
pindex[0] = NS_create_wallstrip_point(px1, nh->bot + 0, pz1);
pindex[1] = NS_create_wallstrip_point(px2, nh->bot + 0, pz2);
pindex[2] = NS_create_wallstrip_point(px1, nh->bot + 2, pz1);
pindex[3] = NS_create_wallstrip_point(px2, nh->bot + 2, pz2);
px1 += dx >> 2;
pz1 += dz >> 2;
px2 += dx >> 2;
pz2 += dz >> 2;
pindex[4] = NS_create_wallstrip_point(px1, nh->bot + 3, pz1);
pindex[5] = NS_create_wallstrip_point(px2, nh->bot + 3, pz2);
px1 += dx >> 2;
pz1 += dz >> 2;
px2 += dx >> 2;
pz2 += dz >> 2;
pindex[6] = NS_create_wallstrip_point(px1, nh->bot + 8, pz1);
pindex[7] = NS_create_wallstrip_point(px2, nh->bot + 8, pz2);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP1);
p[0] = pindex[2];
p[1] = pindex[3];
p[2] = pindex[4];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP2);
p[0] = pindex[4];
p[1] = pindex[5];
p[2] = pindex[6];
p[3] = pindex[7];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP3);
}
else
if (curve < 8)
{
//
// Inside curvey bits.
//
switch(curve)
{
case NS_HI_CURVE_ASS:
px = sx + 1 << 8;
pz = sz + 1 << 8;
dx1 = 0;
dz1 = -1;
dx2 = -1;
dz2 = 0;
break;
case NS_HI_CURVE_ALS:
px = sx + 0 << 8;
pz = sz + 1 << 8;
dx1 = +1;
dz1 = 0;
dx2 = 0;
dz2 = -1;
break;
case NS_HI_CURVE_ASL:
px = sx + 1 << 8;
pz = sz + 0 << 8;
dx1 = -1;
dz1 = 0;
dx2 = 0;
dz2 = +1;
break;
case NS_HI_CURVE_ALL:
px = sx + 0 << 8;
pz = sz + 0 << 8;
dx1 = 0;
dz1 = +1;
dx2 = +1;
dz2 = 0;
break;
default:
ASSERT(0);
break;
}
//
// Create the points and faces.
//
pindex[ 0] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 0, nh->bot + 0, pz + dz1 * 0 + dz2 * 0);
pindex[ 1] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 0, nh->bot + 2, pz + dz1 * 0 + dz2 * 0);
pindex[ 2] = NS_create_wallstrip_point(px + dx1 * 64 + dx2 * 64, nh->bot + 3, pz + dz1 * 64 + dz2 * 64);
pindex[ 3] = NS_create_wallstrip_point(px + dx1 * 160 + dx2 * 160, nh->bot + 8, pz + dz1 * 160 + dz2 * 160);
pindex[ 4] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 256, nh->bot + 0, pz + dz1 * 0 + dz2 * 256);
pindex[ 5] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 256, nh->bot + 2, pz + dz1 * 0 + dz2 * 256);
pindex[ 6] = NS_create_wallstrip_point(px + dx1 * 64 + dx2 * 256, nh->bot + 3, pz + dz1 * 64 + dz2 * 256);
pindex[ 7] = NS_create_wallstrip_point(px + dx1 * 128 + dx2 * 256, nh->bot + 8, pz + dz1 * 128 + dz2 * 256);
pindex[ 8] = NS_create_wallstrip_point(px + dx1 * 256 + dx2 * 0, nh->bot + 0, pz + dz1 * 256 + dz2 * 0);
pindex[ 9] = NS_create_wallstrip_point(px + dx1 * 256 + dx2 * 0, nh->bot + 2, pz + dz1 * 256 + dz2 * 0);
pindex[10] = NS_create_wallstrip_point(px + dx1 * 256 + dx2 * 64, nh->bot + 3, pz + dz1 * 256 + dz2 * 64);
pindex[11] = NS_create_wallstrip_point(px + dx1 * 256 + dx2 * 128, nh->bot + 8, pz + dz1 * 256 + dz2 * 128);
p[0] = pindex[8];
p[1] = pindex[0];
p[2] = pindex[9];
p[3] = pindex[1];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP1);
p[0] = pindex[0];
p[1] = pindex[4];
p[2] = pindex[1];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP1);
p[0] = pindex[9];
p[1] = pindex[1];
p[2] = pindex[10];
p[3] = pindex[2];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP4);
p[0] = pindex[1];
p[1] = pindex[5];
p[2] = pindex[2];
p[3] = pindex[6];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP5);
p[0] = pindex[10];
p[1] = pindex[2];
p[2] = pindex[11];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP6);
p[0] = pindex[2];
p[1] = pindex[6];
p[2] = pindex[3];
p[3] = pindex[7];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP7);
}
else
{
//
// Outside curvey bits.
//
switch(curve)
{
case NS_HI_CURVE_OSS:
px = sx + 1 << 8;
pz = sz + 1 << 8;
dx1 = 0;
dz1 = -1;
dx2 = -1;
dz2 = 0;
break;
case NS_HI_CURVE_OLS:
px = sx + 0 << 8;
pz = sz + 1 << 8;
dx1 = +1;
dz1 = 0;
dx2 = 0;
dz2 = -1;
break;
case NS_HI_CURVE_OSL:
px = sx + 1 << 8;
pz = sz + 0 << 8;
dx1 = -1;
dz1 = 0;
dx2 = 0;
dz2 = +1;
break;
case NS_HI_CURVE_OLL:
px = sx + 0 << 8;
pz = sz + 0 << 8;
dx1 = 0;
dz1 = +1;
dx2 = +1;
dz2 = 0;
break;
default:
ASSERT(0);
break;
}
pindex[0] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 0, nh->bot + 2, pz + dz1 * 0 + dz2 * 0);
pindex[1] = NS_create_wallstrip_point(px + dx1 * 64 + dx2 * 64, nh->bot + 3, pz + dz1 * 64 + dz2 * 64);
pindex[2] = NS_create_wallstrip_point(px + dx1 * 96 + dx2 * 96, nh->bot + 8, pz + dz1 * 96 + dz2 * 96);
pindex[3] = NS_create_wallstrip_point(px + dx1 * 64 + dx2 * 0, nh->bot + 3, pz + dz1 * 64 + dz2 * 0);
pindex[4] = NS_create_wallstrip_point(px + dx1 * 128 + dx2 * 0, nh->bot + 8, pz + dz1 * 128 + dz2 * 0);
pindex[5] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 64, nh->bot + 3, pz + dz1 * 0 + dz2 * 64);
pindex[6] = NS_create_wallstrip_point(px + dx1 * 0 + dx2 * 128, nh->bot + 8, pz + dz1 * 0 + dz2 * 128);
p[0] = pindex[3];
p[1] = pindex[0];
p[2] = pindex[1];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP8);
p[0] = pindex[3];
p[1] = pindex[1];
p[2] = pindex[4];
p[3] = pindex[2];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP9);
p[0] = pindex[1];
p[1] = pindex[5];
p[2] = pindex[2];
p[3] = pindex[6];
NS_add_face(p, NS_PAGE_SWALL, NS_TEXTURE_HSTRIP10);
}
}
void NS_cache_create_curve_top(SLONG sx, SLONG sz)
{
UBYTE pindex[16];
UBYTE curve;
SLONG ox = sx << 8;
SLONG oz = sz << 8;
SLONG p[4];
SLONG px;
SLONG py;
SLONG pz;
NS_Hi *nh;
ASSERT(WITHIN(sx, 1, PAP_SIZE_HI - 2));
ASSERT(WITHIN(sz, 1, PAP_SIZE_HI - 2));
nh = &NS_hi[sx][sz];
ASSERT(NS_HI_TYPE(nh) == NS_HI_TYPE_CURVE);
curve = nh->water; // We use the water field to identify the type of curve.
switch(curve)
{
case NS_HI_CURVE_XS:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT1);
break;
case NS_HI_CURVE_XL:
px = ox + 128;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT2);
break;
case NS_HI_CURVE_ZS:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 128;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 128;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT3);
break;
case NS_HI_CURVE_ZL:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz + 128;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz + 128;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT4);
break;
case NS_HI_CURVE_ASS:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 128;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 96;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 96;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT5);
break;
case NS_HI_CURVE_ALS:
px = ox + 128;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 160;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 96;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 128;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT6);
break;
case NS_HI_CURVE_ASL:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz + 128;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 96;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz + 160;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT7);
break;
case NS_HI_CURVE_ALL:
px = ox + 160;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz + 160;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz + 128;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT8);
break;
case NS_HI_CURVE_OSS:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 160;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 160;
pindex[4] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 128;
pindex[5] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[4];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT9);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[4];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT10);
break;
case NS_HI_CURVE_OLS:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 128;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 96;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 160;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[4] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[5] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[2];
p[3] = pindex[3];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT11);
p[0] = pindex[3];
p[1] = pindex[1];
p[2] = pindex[4];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT12);
break;
case NS_HI_CURVE_OSL:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 160;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz + 96;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz + 128;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[4] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[5] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[4];
p[3] = pindex[2];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT13);
p[0] = pindex[2];
p[1] = pindex[3];
p[2] = pindex[4];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT14);
break;
case NS_HI_CURVE_OLL:
px = ox;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz + 128;
pindex[0] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 96;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz + 96;
pindex[1] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 128;
py = NS_hi[sx + 0][sz + 0].top;
pz = oz + 0;
pindex[2] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 0].top;
pz = oz + 0;
pindex[3] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox;
py = NS_hi[sx + 0][sz + 1].top;
pz = oz + 256;
pindex[4] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
px = ox + 256;
py = NS_hi[sx + 1][sz + 1].top;
pz = oz + 256;
pindex[5] = NS_create_wallstrip_point(px, py, pz, NS_NORM_YL);
p[0] = pindex[0];
p[1] = pindex[1];
p[2] = pindex[4];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT15);
p[0] = pindex[2];
p[1] = pindex[3];
p[2] = pindex[1];
p[3] = pindex[5];
NS_add_face(p, NS_PAGE_ROCK, NS_TEXTURE_CT16);
break;
}
}
//
// Creates the curvey bits in a lo-res mapsquare
//
void NS_cache_create_curves(UBYTE mx, UBYTE mz)
{
SLONG x;
SLONG z;
SLONG sx;
SLONG sz;
NS_Hi *nh;
ASSERT(WITHIN(mx, 1, PAP_SIZE_LO - 2));
ASSERT(WITHIN(mz, 1, PAP_SIZE_LO - 2));
//
// The sewer points and faces of the curve only.
//
NS_search_start = NS_scratch_point_upto;
NS_search_end = NS_scratch_point_upto;
for (x = 0; x < 4; x++)
for (z = 0; z < 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_CURVE)
{
NS_cache_create_curve_sewer(sx, sz);
//
// So we can use the points we've just created again.
//
NS_search_end = NS_scratch_point_upto;
}
}
//
// The top of the walls of the sewer system.
//
NS_search_start = NS_scratch_point_upto;
NS_search_end = NS_scratch_point_upto;
for (x = 0; x < 4; x++)
for (z = 0; z < 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_CURVE)
{
NS_cache_create_curve_top(sx, sz);
//
// So we can use the points we've just created again.
//
NS_search_end = NS_scratch_point_upto;
}
}
}
void NS_cache_create_falls(UBYTE mx, UBYTE mz, NS_Cache *nc)
{
SLONG i;
SLONG x;
SLONG z;
SLONG sx;
SLONG sz;
SLONG dx;
SLONG dz;
SLONG nx;
SLONG nz;
SLONG fall;
NS_Hi *nh;
NS_Hi *nh2;
NS_Fall *nf;
ASSERT(WITHIN(mx, 1, PAP_SIZE_LO - 2));
ASSERT(WITHIN(mz, 1, PAP_SIZE_LO - 2));
for (x = 0; x < 4; x++)
for (z = 0; z < 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz];
if (NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE && NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK)
{
//
// Look for water on a higher level.
//
const struct
{
SBYTE dx;
SBYTE dz;
} dir[4] =
{
{+1, 0},
{-1, 0},
{0, +1},
{0, -1}
};
for (i = 0; i < 4; i++)
{
dx = dir[i].dx;
dz = dir[i].dz;
nx = sx + dx;
nz = sz + dz;
ASSERT(WITHIN(nx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(nz, 0, PAP_SIZE_HI - 1));
nh2 = &NS_hi[nx][nz];
if (nh2->water && (NS_HI_TYPE(nh2) != NS_HI_TYPE_CURVE) && (NS_HI_TYPE(nh2) != NS_HI_TYPE_ROCK))
{
//
// Found a neighbouring square with water.
//
if ((nh->water && nh2->water > nh->water) || (!nh->water && nh2->water > nh->bot))
{
//
// Found a waterfall!
//
if (NS_fall_free)
{
//
// Take a waterfall out of the linked list.
//
ASSERT(WITHIN(NS_fall_free, 1, NS_MAX_FALLS - 1));
fall = NS_fall_free;
nf = &NS_fall[fall];
NS_fall_free = nf->next;
//
// Create the waterfall structure.
//
nf->x = sx;
nf->z = sz;
nf->dx = dx;
nf->dz = dz;
nf->top = nh2->water;
nf->bot = (nh->water) ? nh->water : nh->bot;
nf->counter = 0;
//
// Add it to the linked list for this cache element.
//
nf->next = nc->fall;
nc->fall = fall;
}
}
}
}
}
}
}
//
// Creates the walls around the grates.
//
void NS_cache_create_grates(UBYTE mx, UBYTE mz)
{
SLONG i;
SLONG x;
SLONG z;
SLONG x1;
SLONG y1;
SLONG z1;
SLONG x2;
SLONG y2;
SLONG z2;
SLONG sx;
SLONG sz;
SLONG fall;
NS_Hi *nh;
SLONG p[4];
static struct
{
SBYTE dx;
SBYTE dz;
UWORD norm;
} order[4] =
{
{+1, 0, NS_NORM_XS},
{-1, 0, NS_NORM_XL},
{0, +1, NS_NORM_ZS},
{0, -1, NS_NORM_ZL}
};
ASSERT(WITHIN(mx, 1, PAP_SIZE_LO - 2));
ASSERT(WITHIN(mz, 1, PAP_SIZE_LO - 2));
for (x = 0; x < 4; x++)
for (z = 0; z < 4; z++)
{
sx = (mx << 2) + x;
sz = (mz << 2) + z;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz];
if (nh->packed & NS_HI_FLAG_GRATE)
{
//
// Create each side of the wall under the grate.
//
y1 = nh->bot;
y2 = nh->bot - 8;
for (i = 0; i < 4; i++)
{
x1 = (sx << 8) + 0x80 + (order[i].dx + (-order[i].dz) << 7);
z1 = (sz << 8) + 0x80 + (order[i].dz + (+order[i].dx) << 7);
x2 = (sx << 8) + 0x80 + (order[i].dx - (-order[i].dz) << 7);
z2 = (sz << 8) + 0x80 + (order[i].dz - (+order[i].dx) << 7);
p[0] = NS_scratch_point_upto + 0;
p[1] = NS_scratch_point_upto + 1;
p[2] = NS_scratch_point_upto + 2;
p[3] = NS_scratch_point_upto + 3;
NS_add_point(x1, y2, z1, order[i].norm);
NS_add_point(x2, y2, z2, order[i].norm);
NS_add_point(x1, y1, z1, NS_NORM_BLACK);
NS_add_point(x2, y1, z2, NS_NORM_BLACK);
NS_add_face(p, NS_PAGE_STONE, NS_TEXTURE_FULL);
}
}
}
}
#if WE_CALCULATE_OUR_OWN_LIGHT_POSITIONS
//
// Returns where the light for a lo-res mapsquare should go. Returns FALSE
// if there is no light in this mapsquare.
//
SLONG NS_cache_find_light(
UBYTE mx,
UBYTE mz,
UBYTE *light_x,
UBYTE *light_y,
UBYTE *light_z)
{
SLONG i;
SLONG sx;
SLONG sz;
SLONG dmx;
SLONG dmz;
SLONG map_x;
SLONG map_z;
SLONG dlx;
SLONG dlz;
SLONG dist;
SLONG best_x;
SLONG best_y;
SLONG best_z;
SLONG best_score = -INFINITY;
SLONG lx;
SLONG ly;
SLONG lz;
SLONG score;
NS_Lo *nl;
NS_Lo *nl2;
NS_Hi *nh;
NS_Cache *nc;
//
// The coordinates of this mapsquare.
//
map_x = mx << PAP_SHIFT_LO;
map_z = mz << PAP_SHIFT_LO;
//
// Look for lights in the surrounding mapsquares.
//
struct
{
SLONG x;
SLONG z;
} other_light[8];
SLONG other_light_upto = 0;
ASSERT(WITHIN(mx, 1, PAP_SIZE_LO - 2));
ASSERT(WITHIN(mz, 1, PAP_SIZE_LO - 2));
nl = &NS_lo[mx][mz];
for (dmx = -1; dmx <= +1; dmx += 1)
for (dmz = -1; dmz <= +1; dmz += 1)
{
if (dmx == 0 &&
dmz == 0)
{
//
// Ignore our mapsquare!
//
continue;
}
ASSERT(WITHIN(mx + dmx, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(mz + dmz, 0, PAP_SIZE_LO - 1));
nl2 = &NS_lo[mx + dmx][mz + dmz];
if (nl2->cache)
{
ASSERT(WITHIN(nl2->cache, 1, NS_MAX_CACHES - 1));
nc = &NS_cache[nl2->cache];
//
// Found a neighbouring light.
//
other_light[other_light_upto].x = nc->light_x + (dmx * 128);
other_light[other_light_upto].z = nc->light_z + (dmz * 128);
other_light_upto += 1;
}
}
for (sx = 1; sx < 3; sx++)
for (sz = 1; sz < 3; sz++)
{
ASSERT(WITHIN((mx << 2) + sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN((mz << 2) + sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[(mx << 2) + sx][(mz << 2) + sz];
switch(NS_HI_TYPE(nh))
{
case NS_HI_TYPE_SEWER:
case NS_HI_TYPE_STONE:
lx = sx << 5;
lz = sz << 5;
lx += 16;
lz += 16;
ly = nh->bot + 8;
//
// Score this selection.
//
score = 1;
//
// Prefer squares in the middle.
//
if (sx == 1 || sx == 2) {score += 100;}
if (sz == 1 || sz == 2) {score += 100;}
//
// Check the distances from other lights.
//
for (i = 0; i < other_light_upto; i++)
{
dlx = abs(lx - other_light[i].x);
dlz = abs(lz - other_light[i].z);
dist = dlx + dlz;
if (dist == 128) {score += 100;}
else if (dist > 128) {score += 10;}
else if (dist < 96) {score -= 10000;}
}
if (score > best_score)
{
best_score = score;
best_x = lx;
best_y = ly;
best_z = lz;
}
break;
default:
//
// Can't have light on any other square type.
//
break;
}
}
if (best_score <= 0)
{
//
// No decent place to put a light here.
//
return FALSE;
}
*light_x = best_x;
*light_y = best_y;
*light_z = best_z;
return TRUE;
}
#endif
SLONG NS_cache_create(UBYTE mx, UBYTE mz)
{
SLONG dmx;
SLONG dmz;
NS_Cache *nc;
NS_Lo *nl;
SLONG c_index;
SLONG memory_in_bytes;
SLONG memory_points;
SLONG memory_faces;
//
// Make sure this square is uncached and there is a
// free cache entry for it.
//
ASSERT(WITHIN(mx, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(mz, 0, PAP_SIZE_LO - 1));
ASSERT(NS_lo[mx][mz].cache == NULL);
ASSERT(NS_cache_free != NULL);
if (mx == PAP_SIZE_LO - 1 ||
mz == PAP_SIZE_LO - 1 ||
mx == 0 ||
mz == 0)
{
//
// We can't generate the edge of the map.
//
return FALSE;
}
//
// We create points and faces in the scratch buffer first
// and then (once we know how much memory we need) we allocated
// the memory off the heap and copy the data across.
//
NS_scratch_point_upto = 0;
NS_scratch_face_upto = 0;
//
// The origin of this square.
//
NS_scratch_origin_x = mx << PAP_SHIFT_LO;
NS_scratch_origin_z = mz << PAP_SHIFT_LO;
//
// Get our cache element from the free list.
//
c_index = NS_cache_free;
ASSERT(WITHIN(c_index, 1, NS_MAX_CACHES - 1));
nc = &NS_cache[c_index];
NS_cache_free = nc->next;
//
// All the lights that could effect this square.
//
NS_slight_upto = 0;
for (dmx = -1; dmx <= +1; dmx++)
for (dmz = -1; dmz <= +1; dmz++)
{
ASSERT(WITHIN(mx + dmx, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(mz + dmz, 0, PAP_SIZE_LO - 1));
nl = &NS_lo[mx + dmx][mz + dmz];
if (nl->light_y)
{
ASSERT(WITHIN(NS_slight_upto, 0, NS_MAX_SLIGHTS - 1));
NS_slight[NS_slight_upto].x = nl->light_x + dmx * 128;
NS_slight[NS_slight_upto].z = nl->light_z + dmz * 128;
NS_slight[NS_slight_upto].y = nl->light_y;
NS_slight_upto += 1;
}
}
//
// Create the horizontal squares into the scratch buffers.
//
NS_cache_create_floors(mx, mz);
NS_cache_create_walls (mx, mz);
NS_cache_create_curves(mx, mz);
NS_cache_create_grates(mx, mz);
//
// Setup the cache element.
//
nc->next = NULL;
nc->used = TRUE;
nc->map_x = mx;
nc->map_z = mz;
nc->num_points = NS_scratch_point_upto;
nc->num_faces = NS_scratch_face_upto;
nc->fall = NULL;
memory_points = nc->num_points * sizeof(NS_Point);
memory_faces = nc->num_faces * sizeof(NS_Face);
memory_in_bytes = memory_points + memory_faces;
//
// Allocate memory and copy data over from the scratch buffers.
//
nc->memory = (UBYTE *) HEAP_get(memory_in_bytes);
ASSERT(nc->memory != NULL);
memcpy(nc->memory, NS_scratch_point, memory_points);
memcpy(nc->memory + memory_points, NS_scratch_face, memory_faces);
//
// Add the waterfalls.
//
NS_cache_create_falls(mx, mz, nc);
//
// Link the mapsquare to this cache element
//
NS_lo[mx][mz].cache = c_index;
return TRUE;
}
void NS_cache_destroy(UBYTE cache)
{
SLONG memory_in_bytes;
SLONG fall;
SLONG next;
NS_Fall *nf;
NS_Cache *nc;
ASSERT(WITHIN(cache, 1, NS_MAX_CACHES - 1));
nc = &NS_cache[cache];
ASSERT(nc->used);
ASSERT(WITHIN(nc->map_x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(nc->map_z, 0, PAP_SIZE_LO - 1));
//
// Returns the memory to the heap.
//
memory_in_bytes = nc->num_points * sizeof(NS_Point);
memory_in_bytes += nc->num_faces * sizeof(NS_Face);
HEAP_give(nc->memory, memory_in_bytes);
//
// Put the waterfalls back into the free list.
//
fall = nc->fall;
while(fall)
{
ASSERT(WITHIN(fall, 1, NS_MAX_FALLS - 1));
nf = &NS_fall[fall];
next = nf->next;
//
// Add to the free list.
//
nf->next = NS_fall_free;
NS_fall_free = fall;
fall = next;
}
//
// Mark as unused and return to the free list.
//
nc->used = FALSE;
nc->next = NS_cache_free;
NS_cache_free = cache;
//
// Mark the mapsquare as uncached.
//
NS_lo[nc->map_x][nc->map_z].cache = NULL;
}
void NS_cache_fini()
{
//
// It does slightly more than necessary!
//
NS_cache_init();
}
SLONG NS_calc_height_at(SLONG x, SLONG z)
{
NS_Hi *nh;
SLONG ans;
SLONG mx = x >> PAP_SHIFT_HI;
SLONG mz = z >> PAP_SHIFT_HI;
if (!WITHIN(mx, 0, PAP_SIZE_HI - 1) ||
!WITHIN(mz, 0, PAP_SIZE_HI - 1))
{
return 0;
}
nh = &NS_hi[mx][mz];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_ROCK)
{
return -0x200;
}
else
{
ans = (nh->bot << 5) + (-32 * 0x100);
}
return ans;
}
SLONG NS_calc_splash_height_at(SLONG x, SLONG z)
{
NS_Hi *nh;
SLONG ans;
SLONG mx = x >> PAP_SHIFT_HI;
SLONG mz = z >> PAP_SHIFT_HI;
if (!WITHIN(mx, 0, PAP_SIZE_HI - 1) ||
!WITHIN(mz, 0, PAP_SIZE_HI - 1))
{
return 0;
}
nh = &NS_hi[mx][mz];
if (NS_HI_TYPE(nh) == NS_HI_TYPE_ROCK)
{
return -0x200;
}
else
{
if (nh->water)
{
ans = (nh->water << 5) + (-32 * 0x100);
}
else
{
ans = (nh->bot << 5) + (-32 * 0x100);
}
}
return ans;
}
void NS_slide_along(
SLONG x1, SLONG y1, SLONG z1,
SLONG *x2, SLONG *y2, SLONG *z2,
SLONG radius)
{
SLONG i;
SLONG height;
SLONG collided = FALSE;
SLONG mx;
SLONG mz;
SLONG dx;
SLONG dz;
SLONG vx1;
SLONG vz1;
SLONG vx2;
SLONG vz2;
SLONG sx1;
SLONG sz1;
SLONG sx2;
SLONG sz2;
SLONG sradius;
NS_Hi *nh;
const struct {SBYTE dx; SBYTE dz;} order[4] =
{
{+1, 0},
{-1, 0},
{0, +1},
{0, -1}
};
SLONG collide;
//
// Keep on the map!
//
#define NS_SLIDE_MIN ((1 << PAP_SHIFT_LO) << 8)
#define NS_SLIDE_MAX (((PAP_SIZE_LO - 1) << PAP_SHIFT_LO) << 8)
if (*x2 < NS_SLIDE_MIN) {*x2 = NS_SLIDE_MIN;}
if (*x2 > NS_SLIDE_MAX) {*x2 = NS_SLIDE_MAX;}
if (*z2 < NS_SLIDE_MIN) {*z2 = NS_SLIDE_MIN;}
if (*z2 > NS_SLIDE_MAX) {*z2 = NS_SLIDE_MAX;}
//
// Put the radius in the same coordinate system as (x,y,z)
//
radius <<= 8;
//
// Collide with the map.
//
for (i = 0; i < 4; i++)
{
mx = (x1 >> 16) + order[i].dx;
mz = (z1 >> 16) + order[i].dz;
ASSERT(WITHIN(mx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(mz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[mx][mz];
switch(NS_HI_TYPE(nh))
{
case NS_HI_TYPE_ROCK:
case NS_HI_TYPE_CURVE:
case NS_HI_TYPE_NOTHING:
collide = TRUE;
break;
default:
//
// What is the height of the top of this square?
//
height = (nh->bot << (5 + 8)) + (-32 * 0x100 * 0x100);
//
// Can step up a quarter of a block.
//
if (*y2 + 0x4000 < height)
{
collide = TRUE;
}
else
{
collide = FALSE;
}
break;
}
if (collide)
{
//
// Collide with the edge of this square.
//
dx = order[i].dx << 7;
dz = order[i].dz << 7;
mx = x1 >> 16;
mz = z1 >> 16;
sx1 = (mx << 8) + 0x80 + dx - dz;
sz1 = (mz << 8) + 0x80 + dz + dx;
sx2 = (mx << 8) + 0x80 + dx + dz;
sz2 = (mz << 8) + 0x80 + dz - dx;
sradius = radius >> 8;
vx1 = x1 >> 8;
vz1 = z1 >> 8;
vx2 = *x2 >> 8;
vz2 = *z2 >> 8;
if (slide_around_sausage(
sx1, sz1,
sx2, sz2,
sradius,
vx1, vz1,
&vx2, &vz2))
{
*x2 = vx2 << 8;
*z2 = vz2 << 8;
}
}
}
}
SLONG NS_inside(SLONG x, SLONG y, SLONG z)
{
return y < NS_calc_height_at(x,z);
}
SLONG NS_los_fail_x;
SLONG NS_los_fail_y;
SLONG NS_los_fail_z;
SLONG NS_there_is_a_los(
SLONG x1, SLONG y1, SLONG z1,
SLONG x2, SLONG y2, SLONG z2)
{
SLONG i;
SLONG x;
SLONG y;
SLONG z;
SLONG dx = x2 - x1;
SLONG dy = y2 - y1;
SLONG dz = z2 - z1;
SLONG len = QDIST3(abs(dx),abs(dy),abs(dz));
SLONG steps = len >> 5;
if(len==0)
{
//
// there is a los for this small distance
//
return(TRUE);
}
dx = (dx << 5) / len;
dy = (dy << 5) / len;
dz = (dz << 5) / len;
x = x1 + dx;
y = y1 + dy;
z = z1 + dz;
for (i = 1; i < steps; i++)
{
if (NS_inside(x,y,z))
{
NS_los_fail_x = x - dx;
NS_los_fail_y = y - dy;
NS_los_fail_z = z - dz;
return FALSE;
}
}
return TRUE;
}
//
// Returns the index of an unused sewer thing or NULL if there
// are no spare sewer things.
//
SLONG NS_get_unused_st(void)
{
SLONG i;
SLONG pick;
NS_St *nst;
//
// Look for an unused object.
//
pick = rand() % (NS_MAX_STS - 1);
pick += 1;
for (i = 0; i < NS_MAX_STS; i++)
{
ASSERT(WITHIN(pick, 1, NS_MAX_STS - 1));
nst = &NS_st[pick];
if (nst->type == NS_ST_TYPE_UNUSED)
{
return pick;
}
pick += 1;
if (pick >= NS_MAX_STS)
{
pick = 1;
}
}
//
// No more sewer things left.
//
return NULL;
}
void NS_add_ladder(SLONG x1, SLONG z1, SLONG x2, SLONG z2, SLONG height)
{
SLONG mx = (x1 + x2 << 7) + ((z2 - z1) << 2) >> PAP_SHIFT_LO;
SLONG mz = (z1 + z2 << 7) - ((x2 - x1) << 2) >> PAP_SHIFT_LO;
if (!WITHIN(mx, 1, PAP_SIZE_LO - 2) ||
!WITHIN(mz, 1, PAP_SIZE_LO - 2))
{
//
// The ladder is off the map!
//
return;
}
NS_Lo *nl = &NS_lo[mx][mz];
SLONG index = NS_get_unused_st();
if (index == NULL)
{
//
// No spare sewer things.
//
return;
}
//
// Create the sewer thing.
//
ASSERT(WITHIN(index, 1, NS_MAX_STS - 1));
NS_St *nst = &NS_st[index];
nst->type = NS_ST_TYPE_LADDER;
nst->ladder.x1 = x1;
nst->ladder.z1 = z1;
nst->ladder.x2 = x2;
nst->ladder.z2 = z2;
nst->ladder.height = height;
//
// Add to the mapwho.
//
nst->next = nl->st;
nl->st = index;
}
void NS_add_prim(
SLONG prim,
SLONG yaw,
SLONG x,
SLONG y,
SLONG z)
{
SLONG mx = x >> PAP_SHIFT_LO;
SLONG mz = z >> PAP_SHIFT_LO;
if (!WITHIN(mx, 1, PAP_SIZE_LO - 2) ||
!WITHIN(mz, 1, PAP_SIZE_LO - 2))
{
//
// The prim is off the map!
//
return;
}
NS_Lo *nl = &NS_lo[mx][mz];
SLONG index = NS_get_unused_st();
if (index == NULL)
{
//
// No spare sewer things.
//
return;
}
ASSERT(WITHIN(index, 1, NS_MAX_STS - 1));
NS_St *nst = &NS_st[index];
//
// Room on this square for another
//
nst->type = NS_ST_TYPE_PRIM;
nst->prim.prim = prim;
nst->prim.yaw = yaw >> 3;
nst->prim.x = (x - (mx << PAP_SHIFT_LO)) >> 3;
nst->prim.z = (z - (mz << PAP_SHIFT_LO)) >> 3;
nst->prim.y = y;
//
// Add to the mapwho.
//
nst->next = nl->st;
nl->st = index;
}
#endif //#ifndef TARGET_DC