1364 lines
22 KiB
C++
1364 lines
22 KiB
C++
//
|
|
// Warehouses
|
|
//
|
|
//
|
|
// Far better it is to dare mighty things, to win glorious
|
|
// triumphs, even though checkered by failure, than to take
|
|
// rank with those poor spirits who neither enjoy nor suffer
|
|
// much, because they live in the gray twilight that knows
|
|
// neither victory nor defeat.
|
|
//
|
|
// THEODORE ROOSEVELT
|
|
//
|
|
|
|
#include "game.h"
|
|
#include "mav.h"
|
|
#include "memory.h"
|
|
#include "supermap.h"
|
|
#include "ware.h"
|
|
#include "night.h"
|
|
#include "ob.h"
|
|
#include "elev.h"
|
|
|
|
|
|
WARE_Ware *WARE_ware;//[WARE_MAX_WARES];
|
|
UWORD WARE_ware_upto;
|
|
|
|
UWORD *WARE_nav;//[WARE_MAX_NAVS];
|
|
UWORD WARE_nav_upto;
|
|
|
|
SBYTE *WARE_height;//[WARE_MAX_HEIGHTS];
|
|
UWORD WARE_height_upto;
|
|
|
|
UWORD *WARE_rooftex;//[WARE_MAX_ROOFTEXES];
|
|
UWORD WARE_rooftex_upto;
|
|
|
|
UBYTE WARE_in;
|
|
|
|
|
|
//
|
|
// The height array for a warehouse.
|
|
//
|
|
|
|
SLONG WARE_calc_height_at(UBYTE ware, SLONG x, SLONG z)
|
|
{
|
|
SLONG ans;
|
|
SLONG index;
|
|
|
|
WARE_Ware *ww;
|
|
|
|
ASSERT(WITHIN(ware, 1, WARE_ware_upto - 1));
|
|
|
|
ww = &WARE_ware[ware];
|
|
|
|
x >>= 8;
|
|
z >>= 8;
|
|
|
|
if (WITHIN(x, ww->minx, ww->maxx) &&
|
|
WITHIN(z, ww->minz, ww->maxz))
|
|
{
|
|
//
|
|
// Into warehouse space.
|
|
//
|
|
|
|
x -= ww->minx;
|
|
z -= ww->minz;
|
|
|
|
index = x * ww->nav_pitch + z;
|
|
|
|
ASSERT(WITHIN(ww->height + index, 0, WARE_height_upto - 1));
|
|
|
|
ans = WARE_height[ww->height + index] << 6;
|
|
|
|
return ans;
|
|
}
|
|
|
|
return 0; // Maybe this should assert...
|
|
}
|
|
|
|
|
|
#ifndef PSX
|
|
|
|
//
|
|
// Returns the bounding box of the given building. The bounding box is exclusive.
|
|
//
|
|
|
|
void WARE_bounding_box(SLONG dbuilding,
|
|
SLONG *bx1, SLONG *bz1,
|
|
SLONG *bx2, SLONG *bz2)
|
|
{
|
|
SLONG i;
|
|
|
|
SLONG x;
|
|
SLONG z;
|
|
|
|
SLONG x1;
|
|
SLONG z1;
|
|
SLONG x2;
|
|
SLONG z2;
|
|
|
|
DBuilding *db;
|
|
DFacet *df;
|
|
|
|
SLONG height;
|
|
|
|
//
|
|
// Initialise the bounding box.
|
|
//
|
|
|
|
x1 = +INFINITY;
|
|
z1 = +INFINITY;
|
|
x2 = -INFINITY;
|
|
z2 = -INFINITY;
|
|
|
|
//
|
|
// Find the building.
|
|
//
|
|
|
|
ASSERT(WITHIN(dbuilding, 1, next_dbuilding - 1));
|
|
|
|
db = &dbuildings[dbuilding];
|
|
|
|
//
|
|
// Go through the dfacets for this building.
|
|
//
|
|
|
|
for (i = db->StartFacet; i < db->EndFacet; i++)
|
|
{
|
|
ASSERT(WITHIN(i, 1, next_dfacet - 1));
|
|
|
|
df = &dfacets[i];
|
|
|
|
if (df->FacetType == STOREY_TYPE_NORMAL)
|
|
{
|
|
x = df->x[0];
|
|
z = df->z[0];
|
|
|
|
if (x < x1) {x1 = x;}
|
|
if (x > x2) {x2 = x;}
|
|
if (z < z1) {z1 = z;}
|
|
if (z > z2) {z2 = z;}
|
|
|
|
x = df->x[1];
|
|
z = df->z[1];
|
|
|
|
if (x < x1) {x1 = x;}
|
|
if (x > x2) {x2 = x;}
|
|
if (z < z1) {z1 = z;}
|
|
if (z > z2) {z2 = z;}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the bounding box.
|
|
//
|
|
|
|
*bx1 = x1;
|
|
*bz1 = z1;
|
|
*bx2 = x2;
|
|
*bz2 = z2;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// The rooftop layer of textures.
|
|
//
|
|
|
|
UWORD WARE_roof_tex[PAP_SIZE_HI][PAP_SIZE_HI];
|
|
|
|
void WARE_init()
|
|
{
|
|
SLONG i;
|
|
SLONG j;
|
|
SLONG x;
|
|
SLONG z;
|
|
SLONG x1;
|
|
SLONG z1;
|
|
SLONG x2;
|
|
SLONG z2;
|
|
SLONG mx;
|
|
SLONG mz;
|
|
SLONG door_x;
|
|
SLONG door_y;
|
|
SLONG door_z;
|
|
SLONG door_angle;
|
|
SLONG dx;
|
|
SLONG dy;
|
|
SLONG dz;
|
|
SLONG rx;
|
|
SLONG rz;
|
|
SLONG sx;
|
|
SLONG sz;
|
|
SLONG bx1;
|
|
SLONG bz1;
|
|
SLONG bx2;
|
|
SLONG bz2;
|
|
SLONG nav_memory;
|
|
SLONG facet;
|
|
SLONG index;
|
|
SLONG walkable;
|
|
|
|
DBuilding *db;
|
|
DFacet *df;
|
|
WARE_Ware *ww;
|
|
OB_Info *oi;
|
|
PrimInfo *pi;
|
|
RoofFace4 *p_f4;
|
|
DWalkable *p_walk;
|
|
|
|
//
|
|
// Load the rooftop textures from the mapfile.
|
|
//
|
|
extern SLONG save_psx;
|
|
|
|
if(!save_psx) // psx has them allready loaded in load_game_map()
|
|
{
|
|
CBYTE *ch;
|
|
|
|
for (ch = ELEV_last_map_loaded; *ch; ch++);
|
|
|
|
ASSERT(ch[-3] == 'i' || ch[-3] == 'I');
|
|
ASSERT(ch[-2] == 'a' || ch[-2] == 'A');
|
|
ASSERT(ch[-1] == 'm' || ch[-1] == 'M');
|
|
|
|
ch[-3] = 'm';
|
|
ch[-2] = 'a';
|
|
ch[-1] = 'p';
|
|
|
|
FILE *handle = MF_Fopen(ELEV_last_map_loaded, "rb");
|
|
|
|
if (!handle)
|
|
{
|
|
memset(WARE_roof_tex, 0, sizeof(UWORD) * PAP_SIZE_HI * PAP_SIZE_HI);
|
|
}
|
|
else
|
|
{
|
|
#define WARE_OFFSET_TO_ROOFTEXTURES (4 + 128*128*12)
|
|
|
|
fseek(handle, WARE_OFFSET_TO_ROOFTEXTURES, SEEK_SET);
|
|
|
|
|
|
fread(WARE_roof_tex, sizeof(UWORD), PAP_SIZE_HI * PAP_SIZE_HI, handle);
|
|
|
|
MF_Fclose(handle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We don't start in a warehouse.
|
|
//
|
|
|
|
WARE_in = NULL;
|
|
|
|
//
|
|
// The height of the map not including the roofs of warehouses.
|
|
//
|
|
|
|
MAV_calc_height_array(TRUE);
|
|
|
|
//
|
|
// Initialise the warehouse structures.
|
|
//
|
|
|
|
memset(WARE_ware, 0, sizeof(WARE_Ware) * WARE_MAX_WARES);
|
|
|
|
WARE_ware_upto = 1;
|
|
|
|
//
|
|
// Initialise warehouse navigation memory.
|
|
//
|
|
|
|
memset(WARE_nav, 0, sizeof(UWORD) * WARE_MAX_NAVS);
|
|
|
|
WARE_nav_upto = 0;
|
|
|
|
//
|
|
// Initialise warehouse height memory.
|
|
//
|
|
|
|
memset(WARE_height, 0, sizeof(UBYTE) * WARE_MAX_HEIGHTS);
|
|
|
|
WARE_height_upto = 0;
|
|
|
|
//
|
|
// Initialise warehouse rooftex memory.
|
|
//
|
|
|
|
memset(WARE_rooftex, 0, sizeof(UWORD) * WARE_MAX_ROOFTEXES);
|
|
|
|
WARE_rooftex_upto = 0;
|
|
|
|
//
|
|
// Clear all the PAP_LO_FLAG_WAREHOUSE flags.
|
|
//
|
|
|
|
for (mx = 0; mx < PAP_SIZE_LO; mx++)
|
|
for (mz = 0; mz < PAP_SIZE_LO; mz++)
|
|
{
|
|
PAP_2LO(mx,mz).Flag &= ~PAP_LO_FLAG_WAREHOUSE;
|
|
}
|
|
|
|
//
|
|
// Look for warehouses.
|
|
//
|
|
|
|
for (i = 1; i < next_dbuilding; i++)
|
|
{
|
|
db = &dbuildings[i];
|
|
|
|
if (db->Type != BUILDING_TYPE_WAREHOUSE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!WITHIN(WARE_ware_upto, 1, WARE_MAX_WARES - 1))
|
|
{
|
|
return;
|
|
}
|
|
|
|
ww = &WARE_ware[WARE_ware_upto];
|
|
|
|
//
|
|
// Link the warehouse and the building to eachother.
|
|
//
|
|
|
|
ww->building = i;
|
|
db->Ware = WARE_ware_upto;
|
|
|
|
//
|
|
// The bounding box the warehouse.
|
|
//
|
|
|
|
WARE_bounding_box(i, &bx1, &bz1, &bx2, &bz2);
|
|
|
|
ww->minx = bx1;
|
|
ww->minz = bz1;
|
|
ww->maxx = bx2 - 1; // The bounding box returned by WARE_bounding_box is exclusive,
|
|
ww->maxz = bz2 - 1;
|
|
|
|
//
|
|
// Set the PAP_LO_FLAG_WAREHOUSE flags.
|
|
//
|
|
|
|
for (mx = bx1; mx < bx2; mx++)
|
|
for (mz = bz1; mz < bz2; mz++)
|
|
{
|
|
if (PAP_2HI(mx,mz).Flags & PAP_FLAG_HIDDEN)
|
|
{
|
|
//
|
|
// Mark the lo-res mapsquare as containing a square inside a warehouse.
|
|
//
|
|
|
|
PAP_2LO(mx>>2,mz>>2).Flag |= PAP_LO_FLAG_WAREHOUSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find the doors of the warehouse.
|
|
//
|
|
|
|
ww->door_upto = 0;
|
|
|
|
//
|
|
// Go through all the facets of this building.
|
|
//
|
|
|
|
for (facet = db->StartFacet; facet < db->EndFacet; facet++)
|
|
{
|
|
df = &dfacets[facet];
|
|
|
|
if (df->FacetType == STOREY_TYPE_DOOR)
|
|
{
|
|
//
|
|
// This is a door. Where should we mavigate to, to be
|
|
// outside the door?
|
|
//
|
|
|
|
x1 = df->x[0] << 8;
|
|
z1 = df->z[0] << 8;
|
|
|
|
x2 = df->x[1] << 8;
|
|
z2 = df->z[1] << 8;
|
|
|
|
dx = x2 - x1 >> 1;
|
|
dz = z2 - z1 >> 1;
|
|
|
|
if (!WITHIN(ww->door_upto, 0, WARE_MAX_DOORS - 1))
|
|
{
|
|
//
|
|
// Already found too many doors!
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The mapsquares the outside and inside of this door are on.
|
|
//
|
|
|
|
ww->door[ww->door_upto].out_x = x1 + dx + dz >> 8;
|
|
ww->door[ww->door_upto].out_z = z1 + dz - dx >> 8;
|
|
|
|
ww->door[ww->door_upto].in_x = x1 + dx - dz >> 8;
|
|
ww->door[ww->door_upto].in_z = z1 + dz + dx >> 8;
|
|
|
|
ww->door_upto += 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate navigation memory.
|
|
//
|
|
|
|
ww->nav_pitch = bz2 - bz1;
|
|
ww->nav = WARE_nav_upto;
|
|
|
|
//
|
|
// How much memory do we need?
|
|
//
|
|
|
|
nav_memory = (bx2 - bx1) * (bz2 - bz1);
|
|
|
|
ASSERT(WARE_nav_upto + nav_memory <= WARE_MAX_NAVS);
|
|
|
|
WARE_nav_upto += nav_memory;
|
|
|
|
//
|
|
// Calculate navigation inside this warehouse.
|
|
//
|
|
|
|
MAV_precalculate_warehouse_nav(WARE_ware_upto);
|
|
|
|
//
|
|
// Remember the height array for this warehouse. It has the same number
|
|
// of elements as the nav array.
|
|
//
|
|
|
|
ASSERT(WARE_height_upto + nav_memory <= WARE_MAX_HEIGHTS);
|
|
|
|
ww->height = WARE_height_upto;
|
|
WARE_height_upto += nav_memory;
|
|
|
|
for (x = ww->minx; x <= ww->maxx; x++)
|
|
for (z = ww->minz; z <= ww->maxz; z++)
|
|
{
|
|
index = (x - ww->minx) * ww->nav_pitch + (z - ww->minz);
|
|
|
|
ASSERT(WITHIN(ww->height + index, 0, WARE_height_upto - 1));
|
|
|
|
WARE_height[ww->height + index] = MAVHEIGHT(x,z);
|
|
}
|
|
|
|
//
|
|
// The rooftop textures of this warehouse.
|
|
//
|
|
|
|
ww->rooftex = WARE_rooftex_upto;
|
|
|
|
for (walkable = db->Walkable; walkable; walkable = p_walk->Next)
|
|
{
|
|
p_walk = &dwalkables[walkable];
|
|
|
|
for (j = p_walk->StartFace4; j < p_walk->EndFace4; j++)
|
|
{
|
|
p_f4 = &roof_faces4[j];
|
|
|
|
ASSERT(WITHIN(WARE_rooftex_upto, 0, WARE_MAX_ROOFTEXES - 1));
|
|
|
|
ASSERT(WITHIN(p_f4->RX&127, 0, PAP_SIZE_HI - 1));
|
|
ASSERT(WITHIN(p_f4->RZ&127, 0, PAP_SIZE_HI - 1));
|
|
|
|
WARE_rooftex[WARE_rooftex_upto++] = WARE_roof_tex[p_f4->RX&127][p_f4->RZ&127];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finished with this warehouse.
|
|
//
|
|
|
|
WARE_ware_upto++;
|
|
}
|
|
|
|
//
|
|
// Work out which OBs are in warehouses and which aren't.
|
|
//
|
|
|
|
for (i = 1; i < OB_ob_upto; i++)
|
|
{
|
|
OB_ob[i].flags &= ~OB_FLAG_WAREHOUSE;
|
|
}
|
|
|
|
MAV_calc_height_array(FALSE);
|
|
|
|
for (i = 1; i < WARE_ware_upto; i++)
|
|
{
|
|
ww = &WARE_ware[i];
|
|
|
|
x1 = ww->minx >> 2;
|
|
z1 = ww->minz >> 2;
|
|
|
|
x2 = ww->maxx >> 2;
|
|
z2 = ww->maxz >> 2;
|
|
|
|
x1 -= 1;
|
|
z1 -= 1;
|
|
|
|
x2 += 1;
|
|
z2 += 1;
|
|
|
|
SATURATE(x1, 0, PAP_SIZE_LO - 1);
|
|
SATURATE(z1, 0, PAP_SIZE_LO - 1);
|
|
|
|
SATURATE(x2, 0, PAP_SIZE_LO - 1);
|
|
SATURATE(z2, 0, PAP_SIZE_LO - 1);
|
|
|
|
for (mx = x1; mx <= x2; mx++)
|
|
for (mz = z1; mz <= z2; mz++)
|
|
{
|
|
for (oi = OB_find(mx,mz); oi->prim; oi++)
|
|
{
|
|
PrimInfo *pi = get_prim_info(oi->prim);
|
|
|
|
if (oi->prim == 23)
|
|
{
|
|
//
|
|
// This prim is never inside. Stuart knows why.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Find which mapsquare the middle of this prim is over.
|
|
//
|
|
|
|
if (oi->prim == PRIM_OBJ_SWITCH_OFF)
|
|
{
|
|
sx = oi->x + (SIN(oi->yaw) >> 10) >> 8;
|
|
sz = oi->z + (COS(oi->yaw) >> 10) >> 8;
|
|
}
|
|
else
|
|
{
|
|
dx = pi->minx + pi->maxx >> 1;
|
|
dz = pi->minz + pi->maxz >> 1;
|
|
|
|
SLONG matrix[4];
|
|
SLONG useangle;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
useangle = -oi->yaw;
|
|
useangle &= 2047;
|
|
|
|
sin_yaw = SIN(useangle);
|
|
cos_yaw = COS(useangle);
|
|
|
|
matrix[0] = cos_yaw;
|
|
matrix[1] = -sin_yaw;
|
|
matrix[2] = sin_yaw;
|
|
matrix[3] = cos_yaw;
|
|
|
|
rx = MUL64(dx, matrix[0]) + MUL64(dz, matrix[1]);
|
|
rz = MUL64(dx, matrix[2]) + MUL64(dz, matrix[3]);
|
|
|
|
sx = oi->x + rx;
|
|
sz = oi->z + rz;
|
|
|
|
sx >>= 8;
|
|
sz >>= 8;
|
|
}
|
|
|
|
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
|
|
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
|
|
|
|
if (oi->y + pi->maxy < (MAVHEIGHT(sx,sz) << 6) - 0x20)
|
|
{
|
|
OB_ob[oi->index].flags |= OB_FLAG_WAREHOUSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
|
|
//
|
|
// Put in the warehouse-door prims.
|
|
//
|
|
|
|
for (i = 1; i < WARE_ware_upto; i++)
|
|
{
|
|
ww = &WARE_ware[i];
|
|
|
|
for (j = 0; j < ww->door_upto; j++)
|
|
{
|
|
//
|
|
// Where should this door go?
|
|
//
|
|
|
|
x1 = (ww->door[j].in_x << 8) + 0x80;
|
|
z1 = (ww->door[j].in_z << 8) + 0x80;
|
|
|
|
x2 = (ww->door[j].out_x << 8) + 0x80;
|
|
z2 = (ww->door[j].out_z << 8) + 0x80;
|
|
|
|
door_x = x1 + x2 >> 1;
|
|
door_z = z1 + z2 >> 1;
|
|
|
|
//
|
|
// Is there already a door here?
|
|
//
|
|
|
|
x1 = door_x - 0x100 >> PAP_SHIFT_LO;
|
|
z1 = door_z - 0x100 >> PAP_SHIFT_LO;
|
|
|
|
x2 = door_x + 0x100 >> PAP_SHIFT_LO;
|
|
z2 = door_z + 0x100 >> PAP_SHIFT_LO;
|
|
|
|
for (mx = x1; mx <= x2; mx++)
|
|
for (mz = z1; mz <= z2; mz++)
|
|
{
|
|
for (oi = OB_find(mx,mz); oi->prim; oi++)
|
|
{
|
|
if (oi->prim == 117)
|
|
{
|
|
//
|
|
// This is the door prim. Is it in the right place?
|
|
//
|
|
|
|
if (oi->x == door_x &&
|
|
oi->z == door_z)
|
|
{
|
|
goto already_a_doorframe_here;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// What's the angle of the door?
|
|
//
|
|
|
|
dx = ww->door[j].out_x - ww->door[j].in_x;
|
|
dz = ww->door[j].out_z - ww->door[j].in_z;
|
|
|
|
door_angle = -Arctan(dx,dz);
|
|
door_angle &= 2047;
|
|
|
|
//
|
|
// We need to put in two doors. What is the y-coordinate just
|
|
// outside the door?
|
|
//
|
|
|
|
door_y = PAP_calc_map_height_at(
|
|
door_x + (dx << 2),
|
|
door_z + (dz << 2)) + 0x80;
|
|
|
|
//
|
|
// Create the two doors.
|
|
//
|
|
|
|
OB_create(
|
|
door_x,
|
|
door_y,
|
|
door_z,
|
|
door_angle,
|
|
0,
|
|
0,
|
|
117,
|
|
0,0,0);
|
|
|
|
OB_create(
|
|
door_x,
|
|
door_y,
|
|
door_z,
|
|
(door_angle + 1024) & 2047,
|
|
0,
|
|
0,
|
|
117,
|
|
OB_FLAG_WAREHOUSE,0,0);
|
|
|
|
already_a_doorframe_here:;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
SLONG WARE_old_amb_red;
|
|
SLONG WARE_old_amb_green;
|
|
SLONG WARE_old_amb_blue;
|
|
SLONG WARE_old_amb_norm_x;
|
|
SLONG WARE_old_amb_norm_y;
|
|
SLONG WARE_old_amb_norm_z;
|
|
|
|
void WARE_enter(SLONG building)
|
|
{
|
|
WARE_Ware *ww;
|
|
DBuilding *db;
|
|
|
|
ASSERT(WITHIN(building, 1, next_dbuilding - 1));
|
|
|
|
db = &dbuildings[building];
|
|
|
|
//
|
|
// Make sure this building is a warehouse.
|
|
//
|
|
|
|
ASSERT(db->Type == BUILDING_TYPE_WAREHOUSE);
|
|
ASSERT(WITHIN(db->Ware, 1, WARE_ware_upto - 1));
|
|
|
|
ww = &WARE_ware[db->Ware];
|
|
|
|
//
|
|
// Remember which warehouse we are in.
|
|
//
|
|
|
|
WARE_in = db->Ware;
|
|
|
|
//
|
|
// Invalidate all the cached lighting so when it is recreated it will be
|
|
// correct for the warehouse.
|
|
//
|
|
|
|
NIGHT_destroy_all_cached_info();
|
|
|
|
//
|
|
// Change the ambient light.
|
|
//
|
|
|
|
WARE_old_amb_red = NIGHT_amb_red;
|
|
WARE_old_amb_green = NIGHT_amb_green;
|
|
WARE_old_amb_blue = NIGHT_amb_blue;
|
|
|
|
WARE_old_amb_norm_x = NIGHT_amb_norm_x;
|
|
WARE_old_amb_norm_y = NIGHT_amb_norm_y;
|
|
WARE_old_amb_norm_z = NIGHT_amb_norm_z;
|
|
|
|
NIGHT_amb_red = 45;
|
|
NIGHT_amb_green = 45;
|
|
NIGHT_amb_blue = 45;
|
|
|
|
NIGHT_amb_norm_x = 0;
|
|
NIGHT_amb_norm_y = -255;
|
|
NIGHT_amb_norm_z = 0;
|
|
}
|
|
|
|
void WARE_exit()
|
|
{
|
|
//
|
|
// We aren't in a warehouse anymore.
|
|
//
|
|
|
|
WARE_in = NULL;
|
|
|
|
//
|
|
// Invalidate all the cached lighting so when it is recreated it will be
|
|
// correct for the outside.
|
|
//
|
|
|
|
NIGHT_destroy_all_cached_info();
|
|
|
|
//
|
|
// Restore the ambient light for the outside.
|
|
//
|
|
|
|
NIGHT_amb_red = WARE_old_amb_red;
|
|
NIGHT_amb_green = WARE_old_amb_green;
|
|
NIGHT_amb_blue = WARE_old_amb_blue;
|
|
|
|
NIGHT_amb_norm_x = WARE_old_amb_norm_x;
|
|
NIGHT_amb_norm_y = WARE_old_amb_norm_y;
|
|
NIGHT_amb_norm_z = WARE_old_amb_norm_z;
|
|
}
|
|
|
|
*/
|
|
|
|
MAV_Action WARE_mav_enter(Thing *p_person, UBYTE ware, UBYTE caps)
|
|
{
|
|
UBYTE i;
|
|
UBYTE best_door;
|
|
SLONG best_dist = 0xffff;
|
|
SLONG dx;
|
|
SLONG dz;
|
|
SLONG dist;
|
|
|
|
MAV_Action ans;
|
|
|
|
WARE_Ware *ww;
|
|
|
|
ASSERT(WITHIN(ware, 1, WARE_ware_upto - 1));
|
|
|
|
ww = &WARE_ware[ware];
|
|
|
|
//
|
|
// Which warehouse entrance shall we mav to?
|
|
//
|
|
|
|
for (i = 0; i < ww->door_upto; i++)
|
|
{
|
|
dx = ww->door[i].out_x - (p_person->WorldPos.X >> 16);
|
|
dz = ww->door[i].out_z - (p_person->WorldPos.Z >> 16);
|
|
|
|
dist = abs(dx) + abs(dz);
|
|
|
|
if (best_dist > dist)
|
|
{
|
|
best_dist = dist;
|
|
best_door = i;
|
|
}
|
|
}
|
|
|
|
if (best_dist == 0)
|
|
{
|
|
//
|
|
// The person is already at the entrance square. Make him walk
|
|
// into the warehouse.
|
|
//
|
|
|
|
ans.dest_x = ww->door[best_door].in_x;
|
|
ans.dest_z = ww->door[best_door].in_z;
|
|
ans.action = MAV_ACTION_GOTO;
|
|
ans.dir = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do the mav.
|
|
//
|
|
|
|
ans = MAV_do(
|
|
p_person->WorldPos.X >> 16,
|
|
p_person->WorldPos.Z >> 16,
|
|
ww->door[best_door].out_x,
|
|
ww->door[best_door].out_z,
|
|
caps);
|
|
#ifndef PSX
|
|
#ifndef TARGET_DC
|
|
#ifdef DEBUG
|
|
AENG_world_line(
|
|
p_person->WorldPos.X >> 8,
|
|
p_person->WorldPos.Y >> 8,
|
|
p_person->WorldPos.Z >> 8,
|
|
16,
|
|
0xffffff,
|
|
(ww->door[best_door].out_x << 8) + 0x80,
|
|
0,
|
|
(ww->door[best_door].out_z << 8) + 0x80,
|
|
0,
|
|
0x00ff00,
|
|
TRUE);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
return ans;
|
|
}
|
|
|
|
MAV_Action WARE_mav_inside(Thing *p_person, UBYTE dest_x, UBYTE dest_z, UBYTE caps)
|
|
{
|
|
UBYTE start_x;
|
|
UBYTE start_z;
|
|
|
|
UWORD *old_mav;
|
|
UWORD old_mav_pitch;
|
|
|
|
MAV_Action ma;
|
|
WARE_Ware *ww;
|
|
|
|
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_WAREHOUSE);
|
|
ASSERT(WITHIN(p_person->Genus.Person->Ware, 1, WARE_ware_upto - 1));
|
|
|
|
ww = &WARE_ware[p_person->Genus.Person->Ware];
|
|
|
|
//
|
|
// Make sure the destination is inside the warehouse.
|
|
//
|
|
|
|
ASSERT(WARE_in_floorplan(p_person->Genus.Person->Ware, dest_x, dest_z));
|
|
|
|
//
|
|
// SATURATE TO BE IN THE WAREHOUSE MARK!
|
|
//
|
|
|
|
|
|
//
|
|
// Set the MAV module to use this warehouses' MAV array.
|
|
//
|
|
|
|
old_mav = MAV_nav;
|
|
old_mav_pitch = MAV_nav_pitch;
|
|
|
|
MAV_nav = &WARE_nav[ww->nav];
|
|
MAV_nav_pitch = ww->nav_pitch;
|
|
|
|
//
|
|
// Put the start and destination into warehouse space.
|
|
//
|
|
|
|
start_x = (p_person->WorldPos.X >> 16);
|
|
start_z = (p_person->WorldPos.Z >> 16);
|
|
|
|
ASSERT(WARE_in_floorplan(p_person->Genus.Person->Ware, start_x, start_z));
|
|
|
|
start_x -= ww->minx;
|
|
start_z -= ww->minz;
|
|
|
|
dest_x -= ww->minx;
|
|
dest_z -= ww->minz;
|
|
|
|
//
|
|
// Do the mav.
|
|
//
|
|
|
|
ma = MAV_do(
|
|
start_x,
|
|
start_z,
|
|
dest_x,
|
|
dest_z,
|
|
caps);
|
|
|
|
//
|
|
// Put the answer into worldspace
|
|
//
|
|
|
|
ma.dest_x += ww->minx;
|
|
ma.dest_z += ww->minz;
|
|
|
|
//
|
|
// Restore the old MAV array.
|
|
//
|
|
|
|
MAV_nav = old_mav;
|
|
MAV_nav_pitch = old_mav_pitch;
|
|
|
|
return ma;
|
|
}
|
|
|
|
MAV_Action WARE_mav_exit(Thing *p_person, UBYTE caps)
|
|
{
|
|
UBYTE i;
|
|
UBYTE best_door = 0;
|
|
UBYTE start_x;
|
|
UBYTE start_z;
|
|
UBYTE dest_x;
|
|
UBYTE dest_z;
|
|
SLONG best_dist = 0xffff;
|
|
SLONG dx;
|
|
SLONG dz;
|
|
SLONG dist;
|
|
|
|
UWORD *old_mav;
|
|
UWORD old_mav_pitch;
|
|
|
|
MAV_Action ans;
|
|
WARE_Ware *ww;
|
|
|
|
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_WAREHOUSE);
|
|
ASSERT(WITHIN(p_person->Genus.Person->Ware, 1, WARE_ware_upto - 1));
|
|
|
|
ww = &WARE_ware[p_person->Genus.Person->Ware];
|
|
|
|
//
|
|
// Set the MAV module to use this warehouses' MAV array.
|
|
//
|
|
|
|
old_mav = MAV_nav;
|
|
old_mav_pitch = MAV_nav_pitch;
|
|
|
|
MAV_nav = &WARE_nav[ww->nav];
|
|
MAV_nav_pitch = ww->nav_pitch;
|
|
|
|
//
|
|
// Which warehouse entrance shall we mav to?
|
|
//
|
|
|
|
for (i = 0; i < ww->door_upto; i++)
|
|
{
|
|
dx = ww->door[i].in_x - (p_person->WorldPos.X >> 16);
|
|
dz = ww->door[i].in_z - (p_person->WorldPos.Z >> 16);
|
|
|
|
dist = abs(dx) + abs(dz);
|
|
|
|
SLONG height_in = WARE_calc_height_at(
|
|
p_person->Genus.Person->Ware,
|
|
(ww->door[i].in_x << 8) + 0x80,
|
|
(ww->door[i].in_z << 8) + 0x80);
|
|
|
|
SLONG height_out = PAP_calc_map_height_at(
|
|
(ww->door[i].out_x << 8) + 0x80,
|
|
(ww->door[i].out_z << 8) + 0x80);
|
|
|
|
if (abs(height_out - height_in) < 0x80)
|
|
{
|
|
if (best_dist > dist)
|
|
{
|
|
best_dist = dist;
|
|
best_door = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (best_dist == 0)
|
|
{
|
|
//
|
|
// Already at the exit square. Walk out of the warehouse.
|
|
//
|
|
|
|
ans.dest_x = ww->door[best_door].out_x;
|
|
ans.dest_z = ww->door[best_door].out_z;
|
|
ans.action = MAV_ACTION_GOTO;
|
|
ans.dir = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Put the start and destination into warehouse space.
|
|
//
|
|
|
|
start_x = (p_person->WorldPos.X >> 16);
|
|
start_z = (p_person->WorldPos.Z >> 16);
|
|
|
|
ASSERT(WARE_in_floorplan(p_person->Genus.Person->Ware, start_x, start_z));
|
|
|
|
start_x -= ww->minx;
|
|
start_z -= ww->minz;
|
|
|
|
dest_x = ww->door[best_door].in_x - ww->minx;
|
|
dest_z = ww->door[best_door].in_z - ww->minz;
|
|
|
|
//
|
|
// Do the mav.
|
|
//
|
|
|
|
ans = MAV_do(
|
|
start_x,
|
|
start_z,
|
|
dest_x,
|
|
dest_z,
|
|
caps);
|
|
|
|
ans.dest_x += ww->minx;
|
|
ans.dest_z += ww->minz;
|
|
}
|
|
|
|
//
|
|
// Restore the old MAV array.
|
|
//
|
|
|
|
MAV_nav = old_mav;
|
|
MAV_nav_pitch = old_mav_pitch;
|
|
|
|
return ans;
|
|
}
|
|
|
|
|
|
SLONG WARE_in_floorplan(UBYTE ware, UBYTE x, UBYTE z)
|
|
{
|
|
ASSERT(WITHIN(ware, 1, WARE_ware_upto - 1));
|
|
|
|
WARE_Ware *ww = &WARE_ware[ware];
|
|
|
|
if (WITHIN(x, ww->minx, ww->maxx) &&
|
|
WITHIN(z, ww->minz, ww->maxz))
|
|
{
|
|
if (PAP_2HI(x,z).Flags & PAP_FLAG_HIDDEN)
|
|
{
|
|
//
|
|
// Inside the bounding box of the warehouse and in a building too...
|
|
//
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef PSX
|
|
#ifndef TARGET_DC
|
|
void WARE_debug(void)
|
|
{
|
|
SLONG i;
|
|
SLONG j;
|
|
SLONG k;
|
|
|
|
SLONG x1, y1, z1;
|
|
SLONG x2, y2, z2;
|
|
|
|
WARE_Ware *ww;
|
|
|
|
if (!Keys[KB_T])
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 1; i < WARE_ware_upto; i++)
|
|
{
|
|
ww = &WARE_ware[i];
|
|
|
|
//
|
|
// Draw the doors.
|
|
//
|
|
|
|
for (j = 0; j < ww->door_upto; j++)
|
|
{
|
|
x1 = ww->door[j].in_x << 8;
|
|
z1 = ww->door[j].in_z << 8;
|
|
|
|
x2 = ww->door[j].out_x << 8;
|
|
z2 = ww->door[j].out_z << 8;
|
|
|
|
x1 += 0x80;
|
|
z1 += 0x80;
|
|
|
|
x2 += 0x80;
|
|
z2 += 0x80;
|
|
|
|
y1 = PAP_calc_height_at(x1, z1);
|
|
y2 = PAP_calc_height_at(x2, z2);
|
|
|
|
AENG_world_line(
|
|
x1, y1, z1,
|
|
00,
|
|
0xffffff,
|
|
x2, y2, z2,
|
|
16,
|
|
0x00ff00,
|
|
TRUE);
|
|
}
|
|
|
|
//
|
|
// Draw the MAV info.
|
|
//
|
|
|
|
{
|
|
SLONG x;
|
|
SLONG z;
|
|
|
|
SLONG x1;
|
|
SLONG y1;
|
|
SLONG z1;
|
|
SLONG x2;
|
|
SLONG y2;
|
|
SLONG z2;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
SLONG lx;
|
|
SLONG lz;
|
|
|
|
SLONG index;
|
|
|
|
MAV_Opt *mo;
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
ULONG colour[7] =
|
|
{
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff,
|
|
0x00ffff00,
|
|
0x00ff00ff,
|
|
0x0000ffff,
|
|
0x00ffaa88
|
|
};
|
|
|
|
for (x = ww->minx; x <= ww->maxx; x++)
|
|
for (z = ww->minz; z <= ww->maxz; z++)
|
|
{
|
|
//
|
|
// Draw a blue cross at the height we think the square is at.
|
|
//
|
|
|
|
x1 = x + 0 << 8;
|
|
z1 = z + 0 << 8;
|
|
x2 = x + 1 << 8;
|
|
z2 = z + 1 << 8;
|
|
|
|
y1 =
|
|
y2 = WARE_calc_height_at(i, (x << 8) + 0x80, (z << 8) + 0x80);
|
|
|
|
AENG_world_line(
|
|
x1, y1, z1, 4, 0x00000077,
|
|
x2, y2, z2, 4, 0x00000077,
|
|
TRUE);
|
|
|
|
AENG_world_line(
|
|
x2, y1, z1, 4, 0x00000077,
|
|
x1, y2, z2, 4, 0x00000077,
|
|
TRUE);
|
|
|
|
//
|
|
// Draw the options for leaving this square.
|
|
//
|
|
|
|
index = (x - ww->minx) * ww->nav_pitch + (z - ww->minz);
|
|
|
|
ASSERT(WITHIN(ww->nav + index, 0, WARE_nav_upto - 1));
|
|
|
|
mo = &MAV_opt[WARE_nav[ww->nav + index]];
|
|
|
|
mx = x1 + x2 >> 1;
|
|
mz = z1 + z2 >> 1;
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
dx = order[j].dx;
|
|
dz = order[j].dz;
|
|
|
|
lx = mx + dx * 96;
|
|
lz = mz + dz * 96;
|
|
|
|
lx += dz * (16 * 3);
|
|
lz += -dx * (16 * 3);
|
|
|
|
for (k = 0; k < 8; k++)
|
|
{
|
|
if (mo->opt[j] & (1 << k))
|
|
{
|
|
AENG_world_line(
|
|
mx, y1, mz, 0, 0,
|
|
lx, y2, lz, 9, colour[k],
|
|
TRUE);
|
|
}
|
|
|
|
lx += -dz * 16;
|
|
lz += +dx * 16;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
SLONG WARE_inside(UBYTE ware, SLONG x, SLONG y, SLONG z)
|
|
{
|
|
SLONG index;
|
|
SLONG height;
|
|
|
|
WARE_Ware *ww;
|
|
|
|
ASSERT(WITHIN(ware, 1, WARE_ware_upto -1 ));
|
|
|
|
ww = &WARE_ware[ware];
|
|
|
|
//
|
|
// Inside our floorplan?
|
|
//
|
|
|
|
x >>= 8;
|
|
z >>= 8;
|
|
|
|
if (!WITHIN(x, ww->minx, ww->maxx) ||
|
|
!WITHIN(z, ww->minz, ww->maxz) ||
|
|
!(PAP_2HI(x,z).Flags & PAP_FLAG_HIDDEN))
|
|
{
|
|
//
|
|
// Outside the floorplan of the building.
|
|
//
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Go into warehouse space.
|
|
//
|
|
|
|
x -= ww->minx;
|
|
z -= ww->minz;
|
|
|
|
index = x * ww->nav_pitch + z;
|
|
|
|
ASSERT(WITHIN(ww->height + index, 0, WARE_height_upto - 1));
|
|
|
|
height = WARE_height[ww->height + index] << 6;
|
|
|
|
return y < height;
|
|
}
|
|
|
|
|
|
|
|
SLONG WARE_which_contains(UBYTE x, UBYTE z)
|
|
{
|
|
SLONG i;
|
|
|
|
for (i = 1; i < WARE_ware_upto; i++)
|
|
{
|
|
if (WARE_in_floorplan(i,x,z))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
UBYTE WARE_get_caps(
|
|
UBYTE ware,
|
|
UBYTE x,
|
|
UBYTE z,
|
|
UBYTE dir)
|
|
{
|
|
SLONG index;
|
|
SLONG mo_index;
|
|
|
|
WARE_Ware *ww;
|
|
|
|
ASSERT(WITHIN(ware, 1, WARE_ware_upto -1 ));
|
|
|
|
ww = &WARE_ware[ware];
|
|
|
|
if (!WITHIN(x, ww->minx, ww->maxx) ||
|
|
!WITHIN(z, ww->minz, ww->maxz))
|
|
{
|
|
//
|
|
// Outside the floorplan of the building.
|
|
//
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Go into warehouse space.
|
|
//
|
|
|
|
x -= ww->minx;
|
|
z -= ww->minz;
|
|
|
|
index = x * ww->nav_pitch + z;
|
|
|
|
ASSERT(WITHIN(ww->nav + index, 0, WARE_nav_upto - 1));
|
|
|
|
mo_index = WARE_nav[ww->nav + index];
|
|
|
|
ASSERT(WITHIN(mo_index, 0, MAV_opt_upto - 1));
|
|
|
|
return MAV_opt[mo_index].opt[dir];
|
|
}
|