3288 lines
55 KiB
C++
3288 lines
55 KiB
C++
//
|
|
// Another navigation system.
|
|
//
|
|
|
|
#include "game.h"
|
|
#include "mav.h"
|
|
#ifndef PSX
|
|
#include "c:\fallen\ddengine\headers\aeng.h"
|
|
#endif
|
|
#include "pap.h"
|
|
#include "supermap.h"
|
|
#include "walkable.h"
|
|
#include "memory.h"
|
|
#include "ware.h"
|
|
#include "ob.h"
|
|
|
|
//
|
|
// A prototype here never hurt anyone
|
|
//
|
|
|
|
//
|
|
// The height in stories of each square.
|
|
//
|
|
|
|
//MAV_height_workaround *MAV_height;
|
|
|
|
|
|
//
|
|
// The navigation info. Each value in the nav array is an index
|
|
// into this array.
|
|
//
|
|
|
|
MAV_Opt *MAV_opt;
|
|
SLONG MAV_opt_upto;
|
|
|
|
|
|
//
|
|
// How you can move out of each square.
|
|
//
|
|
|
|
UWORD *MAV_nav;
|
|
SLONG MAV_nav_pitch = 128;
|
|
|
|
|
|
|
|
|
|
void MAV_init()
|
|
{
|
|
SLONG i;
|
|
|
|
MAV_nav_pitch = 128;
|
|
MAV_opt_upto = 0;
|
|
|
|
//
|
|
// Create common MAV_opts first. We need these for the inside2 nav
|
|
// so macke sure they are all here (so we won't have to dynamically
|
|
// allocate them).
|
|
//
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
//
|
|
// If you change this bit of code, make sure you change the corresponding
|
|
// bit of code in INSIDE2_mav_nav_calc().
|
|
//
|
|
|
|
MAV_opt[i].opt[0] = (i & 1) ? 0 : MAV_CAPS_GOTO;
|
|
MAV_opt[i].opt[1] = (i & 2) ? 0 : MAV_CAPS_GOTO;
|
|
MAV_opt[i].opt[2] = (i & 4) ? 0 : MAV_CAPS_GOTO;
|
|
MAV_opt[i].opt[3] = (i & 8) ? 0 : MAV_CAPS_GOTO;
|
|
}
|
|
|
|
MAV_opt_upto = 16;
|
|
}
|
|
|
|
static void StoreMavOpts(SLONG x, SLONG z, UBYTE* opt)
|
|
{
|
|
for (SLONG ii = 0; ii < MAV_opt_upto; ii++)
|
|
{
|
|
if ((MAV_opt[ii].opt[0] == opt[0]) &&
|
|
(MAV_opt[ii].opt[1] == opt[1]) &&
|
|
(MAV_opt[ii].opt[2] == opt[2]) &&
|
|
(MAV_opt[ii].opt[3] == opt[3]))
|
|
{
|
|
SET_MAV_NAV(x, z, ii);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (MAV_opt_upto == MAV_MAX_OPTS)
|
|
{
|
|
TRACE("Run out of MAV opts!\n");
|
|
ASSERT(0);
|
|
}
|
|
else
|
|
{
|
|
MAV_opt[MAV_opt_upto].opt[0] = opt[0];
|
|
MAV_opt[MAV_opt_upto].opt[1] = opt[1];
|
|
MAV_opt[MAV_opt_upto].opt[2] = opt[2];
|
|
MAV_opt[MAV_opt_upto].opt[3] = opt[3];
|
|
|
|
SET_MAV_NAV(x, z, MAV_opt_upto);
|
|
|
|
MAV_opt_upto++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculates the MAV_height array.
|
|
//
|
|
#ifndef PSX
|
|
void MAV_calc_height_array(SLONG ignore_warehouses)
|
|
{
|
|
SLONG i;
|
|
SLONG j;
|
|
|
|
SLONG x;
|
|
SLONG z;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG index;
|
|
SLONG face;
|
|
SLONG faceheight;
|
|
|
|
SLONG height;
|
|
SLONG walk;
|
|
|
|
DBuilding *db;
|
|
PrimFace4 *p_f4;
|
|
RoofFace4 *rf;
|
|
DWalkable *dw;
|
|
PAP_Hi *ph;
|
|
|
|
//
|
|
// Work out the MAV_height array.
|
|
//
|
|
|
|
for (x = 0; x < PAP_SIZE_HI; x++)
|
|
for (z = 0; z < PAP_SIZE_HI; z++)
|
|
{
|
|
//
|
|
// The middle of this mapsquare.
|
|
//
|
|
|
|
mx = x << 8;
|
|
mz = z << 8;
|
|
|
|
mx += 0x80;
|
|
mz += 0x80;
|
|
|
|
if ((PAP_2HI(x,z).Flags & PAP_FLAG_ROOF_EXISTS))
|
|
{
|
|
}
|
|
else
|
|
if ((PAP_2HI(x,z).Flags & PAP_FLAG_HIDDEN) && !ignore_warehouses)
|
|
{
|
|
MAVHEIGHT(x,z) = -127;
|
|
}
|
|
else
|
|
{
|
|
height = PAP_calc_height_at(mx, mz);
|
|
|
|
//
|
|
// Convert to the SBYTE coordinate system in the MAV_height array.
|
|
//
|
|
|
|
height /= 0x40;
|
|
|
|
SATURATE(height, -127, +127);
|
|
|
|
MAVHEIGHT(x,z) = height;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Use the walkable faces to set the height of the hidden squares.
|
|
//
|
|
|
|
for (i = 1; i < next_dbuilding; i++)
|
|
{
|
|
db = &dbuildings[i];
|
|
|
|
if (db->Type == BUILDING_TYPE_WAREHOUSE)
|
|
{
|
|
if (ignore_warehouses)
|
|
{
|
|
//
|
|
// Ignore these roof faces.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
for (walk = db->Walkable; walk; walk = dw->Next)
|
|
{
|
|
dw = &dwalkables[walk];
|
|
|
|
for (j = dw->StartFace4; j < dw->EndFace4; j++)
|
|
{
|
|
rf = &roof_faces4[j];
|
|
|
|
rf->DrawFlags &= ~RFACE_FLAG_NODRAW; // This flag is set later... but shouldn't be set here.
|
|
|
|
if (db->Type == BUILDING_TYPE_WAREHOUSE)
|
|
{
|
|
//
|
|
// Mark this mapsquare as being inside a warehouse (top bit!)
|
|
//
|
|
|
|
ph = &PAP_2HI(rf->RX&127,rf->RZ&127);
|
|
|
|
ph->Texture |= 1 << 15;
|
|
}
|
|
|
|
height = rf->Y;
|
|
height /= 0x40;
|
|
|
|
SATURATE(height, -127, +127);
|
|
|
|
if (MAVHEIGHT(rf->RX&127,rf->RZ&127) < height)
|
|
{
|
|
MAVHEIGHT(rf->RX&127,rf->RZ&127) = height;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Nowadays there are buildings without roofs.
|
|
//
|
|
|
|
for (x = 0; x < PAP_SIZE_HI; x++)
|
|
for (z = 0; z < PAP_SIZE_HI; z++)
|
|
{
|
|
if (MAVHEIGHT(x,z) <= -127)
|
|
{
|
|
if (PAP_2HI(x,z).Flags & PAP_FLAG_HIDDEN)
|
|
{
|
|
MAVHEIGHT(x,z) = 127;
|
|
|
|
PAP_2HI(x,z).Flags |= PAP_FLAG_NOGO;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
for (x = 0; x < PAP_SIZE_LO; x++)
|
|
for (z = 0; z < PAP_SIZE_LO; z++)
|
|
{
|
|
face = PAP_2LO(x,z).Walkable;
|
|
|
|
while(face)
|
|
{
|
|
if (face > 0)
|
|
{
|
|
p_f4 = &prim_faces4[face];
|
|
|
|
//
|
|
// ASSUME FACES DONT SPAN MORE THAN ONE MAPSQUARE!
|
|
//
|
|
|
|
mx = prim_points[p_f4->Points[0]].X + prim_points[p_f4->Points[1]].X + prim_points[p_f4->Points[2]].X + prim_points[p_f4->Points[3]].X >> 10;
|
|
mz = prim_points[p_f4->Points[0]].Z + prim_points[p_f4->Points[1]].Z + prim_points[p_f4->Points[2]].Z + prim_points[p_f4->Points[3]].Z >> 10;
|
|
|
|
if (PAP_2HI(mx,mz).Flags & PAP_FLAG_HIDDEN)
|
|
{
|
|
if(calc_height_on_face((mx << 8) + 0x80, (mz << 8) + 0x80, face,&height))
|
|
{
|
|
|
|
//
|
|
// Convert to the SBYTE coordinate system in the MAV_height array.
|
|
//
|
|
|
|
height /= 0x40;
|
|
|
|
SATURATE(height, -127, +127);
|
|
|
|
if (MAV_height[mx][mz] < height)
|
|
{
|
|
MAV_height[mx][mz] = height;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
face = p_f4->WALKABLE;
|
|
}
|
|
else
|
|
{
|
|
rf = &roof_faces4[-face];
|
|
|
|
//
|
|
// This is a cunning roof face.
|
|
//
|
|
|
|
height = rf->Y / 0x40;
|
|
|
|
SATURATE(height, -127, +127);
|
|
|
|
if (MAV_height[rf->X][rf->Z] < height)
|
|
{
|
|
MAV_height[rf->X][rf->Z] = height;
|
|
}
|
|
|
|
face = rf->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
*/
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Makes sure that nobody mavigates into the given square by walking
|
|
// into it.
|
|
//
|
|
#ifndef PSX
|
|
void MAV_turn_off_square(
|
|
SLONG x,
|
|
SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
UBYTE opt[4];
|
|
|
|
SLONG i;
|
|
SLONG j;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
mx = x - order[i].dx;
|
|
mz = z - order[i].dz;
|
|
|
|
if (WITHIN(mx, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(mz, 0, MAP_HEIGHT - 1))
|
|
{
|
|
ASSERT(WITHIN(MAV_NAV(mx,mz), 0, MAV_opt_upto - 1));
|
|
|
|
opt[0] = MAV_opt[MAV_NAV(mx,mz)].opt[0];
|
|
opt[1] = MAV_opt[MAV_NAV(mx,mz)].opt[1];
|
|
opt[2] = MAV_opt[MAV_NAV(mx,mz)].opt[2];
|
|
opt[3] = MAV_opt[MAV_NAV(mx,mz)].opt[3];
|
|
|
|
opt[i] &= ~MAV_CAPS_GOTO;
|
|
|
|
StoreMavOpts(mx, mz, opt);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef PSX
|
|
|
|
//
|
|
// Makes sure nobody can go into this square in any way.
|
|
//
|
|
|
|
void MAV_turn_off_whole_square(
|
|
SLONG x,
|
|
SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
UBYTE opt[4];
|
|
|
|
SLONG i;
|
|
SLONG j;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
mx = x - order[i].dx;
|
|
mz = z - order[i].dz;
|
|
|
|
if (WITHIN(mx, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(mz, 0, MAP_HEIGHT - 1))
|
|
{
|
|
ASSERT(WITHIN(MAV_NAV(mx,mz), 0, MAV_opt_upto - 1));
|
|
|
|
opt[0] = MAV_opt[MAV_NAV(mx,mz)].opt[0];
|
|
opt[1] = MAV_opt[MAV_NAV(mx,mz)].opt[1];
|
|
opt[2] = MAV_opt[MAV_NAV(mx,mz)].opt[2];
|
|
opt[3] = MAV_opt[MAV_NAV(mx,mz)].opt[3];
|
|
|
|
opt[i] = 0;
|
|
|
|
StoreMavOpts(mx, mz, opt);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Makes sure nobody can go into this square in any way.
|
|
//
|
|
|
|
void MAV_turn_off_whole_square_car(
|
|
SLONG x,
|
|
SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
UBYTE opt[4];
|
|
|
|
SLONG i;
|
|
SLONG j;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
mx = x - order[i].dx;
|
|
mz = z - order[i].dz;
|
|
|
|
if (WITHIN(mx, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(mz, 0, MAP_HEIGHT - 1))
|
|
{
|
|
UBYTE caropt = MAV_CAR(mx, mz);
|
|
|
|
caropt &= ~(1 << i);
|
|
|
|
SET_MAV_CAR(mx, mz, caropt);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// cut off a facet from the car mav
|
|
//
|
|
|
|
void MAV_remove_facet_car(SLONG x1, SLONG z1, SLONG x2, SLONG z2)
|
|
{
|
|
if (x1 == x2)
|
|
{
|
|
if (z1 > z2) SWAP(z1,z2);
|
|
|
|
for (SLONG z = z1; z < z2; z++)
|
|
{
|
|
UBYTE caropt;
|
|
|
|
if (x1 > 0)
|
|
{
|
|
caropt = MAV_CAR(x1 - 1, z);
|
|
caropt &= ~(1 << MAV_DIR_XL);
|
|
SET_MAV_CAR(x1 - 1, z, caropt);
|
|
}
|
|
if (x1 < MAP_WIDTH)
|
|
{
|
|
caropt = MAV_CAR(x1, z);
|
|
caropt &= ~(1 << MAV_DIR_XS);
|
|
SET_MAV_CAR(x1, z, caropt);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(z1 == z2);
|
|
if (x1 > x2) SWAP(x1,x2);
|
|
|
|
for (SLONG x = x1; x < x2; x++)
|
|
{
|
|
UBYTE caropt;
|
|
|
|
if (z1 > 0)
|
|
{
|
|
caropt = MAV_CAR(x, z1 - 1);
|
|
caropt &= ~(1 << MAV_DIR_ZL);
|
|
SET_MAV_CAR(x, z1 - 1, caropt);
|
|
}
|
|
if (z1 < MAP_HEIGHT)
|
|
{
|
|
caropt = MAV_CAR(x, z1);
|
|
caropt &= ~(1 << MAV_DIR_ZS);
|
|
SET_MAV_CAR(x, z1, caropt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Turns off movement in the given direction from the square.
|
|
//
|
|
|
|
void MAV_turn_movement_off(UBYTE mx, UBYTE mz, UBYTE dir)
|
|
{
|
|
SLONG j;
|
|
SLONG mo_index;
|
|
MAV_Opt mo;
|
|
|
|
mo_index = MAV_NAV(mx,mz);
|
|
|
|
ASSERT(WITHIN(mo_index, 0, MAV_opt_upto - 1));
|
|
|
|
mo = MAV_opt[mo_index];
|
|
|
|
mo.opt[dir] &= ~MAV_CAPS_GOTO;
|
|
|
|
StoreMavOpts(mx, mz, mo.opt);
|
|
}
|
|
|
|
|
|
//
|
|
// Turns on movement in the given direction from the square.
|
|
//
|
|
|
|
void MAV_turn_movement_on(UBYTE mx, UBYTE mz, UBYTE dir)
|
|
{
|
|
SLONG j;
|
|
SLONG mo_index;
|
|
MAV_Opt mo;
|
|
|
|
mo_index = MAV_NAV(mx,mz);
|
|
|
|
ASSERT(WITHIN(mo_index, 0, MAV_opt_upto - 1));
|
|
|
|
mo = MAV_opt[mo_index];
|
|
|
|
mo.opt[dir] = MAV_CAPS_GOTO;
|
|
|
|
StoreMavOpts(mx, mz, mo.opt);
|
|
}
|
|
|
|
|
|
|
|
#ifndef PSX
|
|
#ifndef TARGET_DC
|
|
void MAV_precalculate()
|
|
{
|
|
SLONG i;
|
|
|
|
SLONG x;
|
|
SLONG y;
|
|
SLONG z;
|
|
|
|
SLONG x1;
|
|
SLONG y1;
|
|
SLONG z1;
|
|
|
|
SLONG x2;
|
|
SLONG y2;
|
|
SLONG z2;
|
|
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
SLONG tx;
|
|
SLONG tz;
|
|
|
|
SLONG rx;
|
|
SLONG rz;
|
|
|
|
SLONG dh;
|
|
|
|
SLONG useangle;
|
|
SLONG matrix[4];
|
|
SLONG ladder;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
SLONG both_ground;
|
|
|
|
OB_Info *oi;
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
UBYTE opt[4];
|
|
|
|
//
|
|
// Calculates the MAV_height array including warehouses.
|
|
//
|
|
|
|
MAV_calc_height_array(FALSE);
|
|
|
|
//
|
|
// Make the staircase prims change the MAV_height array
|
|
//
|
|
|
|
for (x = 0; x < PAP_SIZE_LO; x++)
|
|
for (z = 0; z < PAP_SIZE_LO; z++)
|
|
{
|
|
for (oi = OB_find(x,z); oi->prim; oi++)
|
|
{
|
|
if (oi->prim == 41)
|
|
{
|
|
//
|
|
// The step prim!
|
|
//
|
|
|
|
if (!(oi->flags & OB_FLAG_WAREHOUSE))
|
|
{
|
|
//
|
|
// Find which mapsquare the middle of this prim is over.
|
|
//
|
|
|
|
PrimInfo *pi = get_prim_info(oi->prim);
|
|
|
|
SLONG mx = pi->minx + pi->maxx >> 1;
|
|
SLONG mz = pi->minz + pi->maxz >> 1;
|
|
|
|
SLONG matrix[4];
|
|
SLONG useangle;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
SLONG rx;
|
|
SLONG rz;
|
|
|
|
SLONG sx;
|
|
SLONG sz;
|
|
|
|
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(mx, matrix[0]) + MUL64(mz, matrix[1]);
|
|
rz = MUL64(mx, matrix[2]) + MUL64(mz, matrix[3]);
|
|
|
|
rx += oi->x;
|
|
rz += oi->z;
|
|
|
|
rx >>= 8;
|
|
rz >>= 8;
|
|
|
|
MAVHEIGHT(rx,rz) = oi->y + 0x40 >> 6;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Work out the nav for each square.
|
|
//
|
|
|
|
for (x = 0; x < PAP_SIZE_HI; x++)
|
|
for (z = 0; z < PAP_SIZE_HI; z++)
|
|
{
|
|
//
|
|
// Look for a nearby ladder.
|
|
//
|
|
|
|
ladder = find_nearby_ladder_colvect_radius(
|
|
(x << 8) + 0x80,
|
|
(z << 8) + 0x80,
|
|
0x100);
|
|
|
|
UBYTE caropts = 0; // car opts
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
opt[i] = 0;
|
|
|
|
dx = order[i].dx;
|
|
dz = order[i].dz;
|
|
|
|
tx = x + dx;
|
|
tz = z + dz;
|
|
|
|
if (WITHIN(tx, 0, PAP_SIZE_HI - 1) &&
|
|
WITHIN(tz, 0, PAP_SIZE_HI - 1))
|
|
{
|
|
//
|
|
// Is one of the squares on a building?
|
|
//
|
|
|
|
if (!(PAP_2HI( x, z).Flags & PAP_FLAG_HIDDEN) &&
|
|
!(PAP_2HI(tx,tz).Flags & PAP_FLAG_HIDDEN))
|
|
{
|
|
both_ground = TRUE;
|
|
}
|
|
else
|
|
{
|
|
both_ground = FALSE;
|
|
}
|
|
|
|
//
|
|
// Can we walk from (x,z) to (tx,tz)?
|
|
//
|
|
|
|
dh = MAVHEIGHT(tx,tz) - MAVHEIGHT(x,z);
|
|
|
|
if ((!both_ground && abs(dh) > 1) || (abs(dh) > 2))
|
|
{
|
|
//
|
|
// There are at different heights, so you cant
|
|
// just walk between the two squares.
|
|
//
|
|
|
|
if (dh < 0)
|
|
{
|
|
//
|
|
// There might be a wall or fence in the way.
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = PAP_calc_map_height_at(x1,z1) + 0x50;
|
|
y2 = PAP_calc_map_height_at(x2,z2) + 0x50;
|
|
|
|
y = MAX(y1,y2);
|
|
|
|
if (there_is_a_los(
|
|
x1, y, z1,
|
|
x2, y, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
//
|
|
// We can always fall down becuase there is nothing in the way.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_FALL_OFF;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If there is a fence in the way, then we can scale the fence.
|
|
//
|
|
|
|
DFacet *df = &dfacets[los_failure_dfacet];
|
|
|
|
if (df->FacetType == STOREY_TYPE_FENCE_FLAT)
|
|
{
|
|
if (df->FacetFlags & FACET_FLAG_UNCLIMBABLE)
|
|
{
|
|
//
|
|
// Unclimbable fence.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can scale this fence.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_CLIMB_OVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (there_is_a_los(x1,y,z1, x2,y,z2,
|
|
LOS_FLAG_IGNORE_PRIMS | LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG | LOS_FLAG_IGNORE_UNDERGROUND_CHECK))
|
|
{
|
|
caropts |= 1 << i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (WITHIN(dh, 2, 4))
|
|
{
|
|
//
|
|
// We can pull ourselves up as long as there isn't a fence in the way.
|
|
//
|
|
|
|
SLONG fx1;
|
|
SLONG fz1;
|
|
SLONG fx2;
|
|
SLONG fz2;
|
|
|
|
fx1 = (x << 8) + 0x80 + (dx << 7) - (dz << 7);
|
|
fz1 = (z << 8) + 0x80 + (dz << 7) + (dx << 7);
|
|
|
|
fx2 = (x << 8) + 0x80 + (dx << 7) + (dz << 7);
|
|
fz2 = (z << 8) + 0x80 + (dz << 7) - (dx << 7);
|
|
|
|
if (does_fence_lie_along_line(
|
|
fx1, fz1,
|
|
fx2, fz2))
|
|
{
|
|
//
|
|
// You can't pull yourself up if there is a fence in the way.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
opt[i] |= MAV_CAPS_PULLUP;
|
|
}
|
|
}
|
|
|
|
if (ladder)
|
|
{
|
|
DFacet *df_ladder;
|
|
|
|
ASSERT(WITHIN(ladder, 1, next_dfacet - 1));
|
|
|
|
df_ladder = &dfacets[ladder];
|
|
|
|
ASSERT(df_ladder->FacetType == STOREY_TYPE_LADDER);
|
|
|
|
//
|
|
// There is a ladder- can we climb up it in this direction?
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
if (two4_line_intersection(
|
|
x1, z1,
|
|
x2, z2,
|
|
df_ladder->x[0] << 8, df_ladder->z[0] << 8,
|
|
df_ladder->x[1] << 8, df_ladder->z[1] << 8))
|
|
{
|
|
//
|
|
// Make sure the ladder reaches to the bottom.
|
|
//
|
|
|
|
if (abs(df_ladder->Y[0] - PAP_calc_map_height_at(x1,z1)) <= 0x50)
|
|
{
|
|
opt[i] |= MAV_CAPS_LADDER_UP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There might be a wall or fence in the way.
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = PAP_calc_map_height_at(x1, z1) + 0x50;
|
|
y2 = PAP_calc_map_height_at(x2, z2) + 0x50;
|
|
|
|
y = MAX(y1,y2);
|
|
|
|
if (there_is_a_los(
|
|
x1, y, z1,
|
|
x2, y, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
//
|
|
// Nothing in the way...
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_GOTO;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If there is a fence in the way, then we can scale the fence.
|
|
//
|
|
|
|
DFacet *df = &dfacets[los_failure_dfacet];
|
|
|
|
if (df->FacetType == STOREY_TYPE_FENCE_FLAT)
|
|
{
|
|
if (df->FacetFlags & FACET_FLAG_UNCLIMBABLE)
|
|
{
|
|
//
|
|
// Unclimbable fence.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can scale this fence.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_CLIMB_OVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (there_is_a_los(x1,y,z1, x2,y,z2,
|
|
LOS_FLAG_IGNORE_PRIMS | LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG | LOS_FLAG_IGNORE_UNDERGROUND_CHECK))
|
|
{
|
|
caropts |= 1 << i;
|
|
}
|
|
}
|
|
|
|
if (!(opt[i] & MAV_CAPS_GOTO) &&
|
|
!(opt[i] & MAV_CAPS_CLIMB_OVER))
|
|
{
|
|
//
|
|
// Now what about jumping one block?
|
|
//
|
|
|
|
tx += dx;
|
|
tz += dz;
|
|
|
|
if (WITHIN(tx, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(tz, 0, MAP_HEIGHT - 1))
|
|
{
|
|
dh = MAVHEIGHT(tx,tz) - MAVHEIGHT(x,z);
|
|
|
|
//
|
|
// Can we jump there?
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = (MAVHEIGHT( x, z) << 6) + 0xa0;
|
|
y2 = (MAVHEIGHT(tx,tz) << 6) + 0xa0;
|
|
|
|
if (there_is_a_los(
|
|
x1, y1, z1,
|
|
x2, y2, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
if (dh < 2)
|
|
{
|
|
opt[i] |= MAV_CAPS_JUMP;
|
|
}
|
|
else
|
|
{
|
|
if (WITHIN(dh, 2, 5))
|
|
{
|
|
opt[i] |= MAV_CAPS_JUMPPULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// What about jumping two blocks?
|
|
//
|
|
|
|
tx += dx;
|
|
tz += dz;
|
|
|
|
if (WITHIN(tx, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(tz, 0, MAP_HEIGHT - 1))
|
|
{
|
|
dh = MAVHEIGHT(tx,tz) - MAVHEIGHT(x,z);
|
|
|
|
if (dh > 4)
|
|
{
|
|
//
|
|
// Can't make this jump
|
|
//
|
|
}
|
|
else
|
|
{
|
|
if (dh > -6)
|
|
{
|
|
//
|
|
// Can we jump there?
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = (MAVHEIGHT( x, z) << 6) + 0xa0;
|
|
y2 = (MAVHEIGHT(tx,tz) << 6) + 0xa0;
|
|
|
|
if (there_is_a_los(
|
|
x1, y1, z1,
|
|
x2, y2, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
opt[i] |= MAV_CAPS_JUMPPULL2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
StoreMavOpts(x, z, opt);
|
|
SET_MAV_CAR(x, z, caropts);
|
|
SET_MAV_SPARE(x, z, 3);
|
|
}
|
|
|
|
//
|
|
// A hack for the staircase prim and the skylights.
|
|
//
|
|
|
|
for (x = 0; x < PAP_SIZE_LO; x++)
|
|
for (z = 0; z < PAP_SIZE_LO; z++)
|
|
{
|
|
for (oi = OB_find(x,z); oi->prim; oi++)
|
|
{
|
|
if (oi->prim == 41)
|
|
{
|
|
//
|
|
// The step prim!
|
|
//
|
|
|
|
if (!(oi->flags & OB_FLAG_WAREHOUSE))
|
|
{
|
|
//
|
|
// Find which mapsquare the middle of this prim is over.
|
|
//
|
|
|
|
PrimInfo *pi = get_prim_info(oi->prim);
|
|
|
|
SLONG mx = pi->minx + pi->maxx >> 1;
|
|
SLONG mz = pi->minz + pi->maxz >> 1;
|
|
|
|
SLONG matrix[4];
|
|
SLONG useangle;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
SLONG rx;
|
|
SLONG rz;
|
|
|
|
SLONG sx;
|
|
SLONG sz;
|
|
|
|
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(mx, matrix[0]) + MUL64(mz, matrix[1]);
|
|
rz = MUL64(mx, matrix[2]) + MUL64(mz, matrix[3]);
|
|
|
|
rx += oi->x;
|
|
rz += oi->z;
|
|
|
|
rx >>= 8;
|
|
rz >>= 8;
|
|
|
|
if (oi->yaw < 256 || oi->yaw > 1792 || WITHIN(oi->yaw, 768, 1280))
|
|
{
|
|
if (MAVHEIGHT(rx,rz) == MAVHEIGHT(rx-1,rz))
|
|
{
|
|
//
|
|
// Walking left-right on a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(rx, rz, MAV_DIR_XS);
|
|
MAV_turn_movement_off(rx - 1, rz, MAV_DIR_XL);
|
|
}
|
|
|
|
if (MAVHEIGHT(rx,rz) == MAVHEIGHT(rx+1,rz))
|
|
{
|
|
//
|
|
// Walking left-right on a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(rx, rz, MAV_DIR_XL);
|
|
MAV_turn_movement_off(rx + 1, rz, MAV_DIR_XS);
|
|
}
|
|
|
|
if (!WITHIN(oi->yaw, 768, 1280))
|
|
{
|
|
if (MAVHEIGHT(rx,rz+1) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(rx,rz, MAV_DIR_ZL);
|
|
MAV_turn_movement_on(rx,rz+1, MAV_DIR_ZS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MAVHEIGHT(rx,rz-1) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(rx,rz, MAV_DIR_ZS);
|
|
MAV_turn_movement_on(rx,rz-1, MAV_DIR_ZL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MAVHEIGHT(rx, rz) == MAVHEIGHT(rx, rz-1))
|
|
{
|
|
//
|
|
// Walking across a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(rx, rz, MAV_DIR_ZS);
|
|
MAV_turn_movement_off(rx, rz - 1, MAV_DIR_ZL);
|
|
}
|
|
|
|
if (MAVHEIGHT(rx, rz) == MAVHEIGHT(rx, rz+1))
|
|
{
|
|
//
|
|
// Walking across a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(rx, rz, MAV_DIR_ZL);
|
|
MAV_turn_movement_off(rx, rz + 1, MAV_DIR_ZS);
|
|
}
|
|
|
|
if (!WITHIN(oi->yaw, 256, 768))
|
|
{
|
|
if (MAVHEIGHT(rx-1,rz) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(rx, rz, MAV_DIR_XS);
|
|
MAV_turn_movement_on(rx-1,rz, MAV_DIR_XL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MAVHEIGHT(rx+1,rz) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(rx, rz, MAV_DIR_XL);
|
|
MAV_turn_movement_on(rx+1, rz, MAV_DIR_XS);
|
|
}
|
|
}
|
|
}
|
|
|
|
WALKABLE_remove_rface(rx,rz);
|
|
}
|
|
}
|
|
else
|
|
if (oi->prim == 226)
|
|
{
|
|
//
|
|
// This is a skylight. Remove the two roof faces that
|
|
// are covered by the skylight.
|
|
//
|
|
|
|
SLONG useangle;
|
|
|
|
useangle = oi->yaw + 1024;
|
|
useangle &= 2047;
|
|
|
|
SLONG mx = oi->x >> 8;
|
|
SLONG mz = oi->z >> 8;
|
|
|
|
SLONG rx = mx + SIGN(SIN(useangle) >> 14);
|
|
SLONG rz = mz + SIGN(COS(useangle) >> 14);
|
|
|
|
WALKABLE_remove_rface(mx,mz);
|
|
WALKABLE_remove_rface(rx,rz);
|
|
}
|
|
else
|
|
if (oi->prim == 227)
|
|
{
|
|
//
|
|
// This is the large skylight. Remove the roof faces that
|
|
// are covered by it.
|
|
//
|
|
|
|
SLONG i;
|
|
SLONG j;
|
|
SLONG useangle;
|
|
|
|
useangle = oi->yaw + 1024;
|
|
useangle &= 2047;
|
|
|
|
SLONG mx = oi->x;
|
|
SLONG mz = oi->z;
|
|
|
|
SLONG rx = SIN(useangle) >> 8;
|
|
SLONG rz = COS(useangle) >> 8;
|
|
|
|
SLONG sx;
|
|
SLONG sz;
|
|
|
|
for (i = -1; i <= 1; i += 1)
|
|
for (j = -1; j <= 1; j += 2)
|
|
{
|
|
sx = mx + rx * i - (rz * j >> 1);
|
|
sz = mz + rz * i + (rx * j >> 1);
|
|
|
|
WALKABLE_remove_rface(
|
|
sx >> 8,
|
|
sz >> 8);
|
|
}
|
|
}
|
|
else
|
|
if (oi->prim == 133)
|
|
{
|
|
//
|
|
// This is the rotating UCPD sign.
|
|
//
|
|
|
|
MAV_turn_off_whole_square(oi->x >> 8, oi->z >> 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
extern SLONG PAP_on_slope(SLONG x,SLONG z,SLONG *angle);
|
|
|
|
//
|
|
// Take all slippy squares out of the mav.
|
|
//
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG angle;
|
|
|
|
for (mx = 0; mx < PAP_SIZE_HI; mx++)
|
|
for (mz = 0; mz < PAP_SIZE_HI; mz++)
|
|
{
|
|
if (PAP_2HI(mx,mz).Flags & PAP_FLAG_HIDDEN)
|
|
{
|
|
//
|
|
// These squares aren't slippy.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
if (PAP_on_slope((mx << 8) + 0x40, (mz << 8) + 0x40, &angle) > 100 ||
|
|
// PAP_on_slope((mx << 8) + 0xc0, (mz << 8) + 0x40, &angle) > 50 ||
|
|
// PAP_on_slope((mx << 8) + 0x40, (mz << 8) + 0xc0, &angle) > 50 ||
|
|
PAP_on_slope((mx << 8) + 0xc0, (mz << 8) + 0xc0, &angle) > 100)
|
|
{
|
|
MAV_turn_off_whole_square(mx,mz);
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove NOGO sqaures from the car map
|
|
{
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG angle;
|
|
|
|
for (mx = 0; mx < PAP_SIZE_HI; mx++)
|
|
for (mz = 0; mz < PAP_SIZE_HI; mz++)
|
|
{
|
|
if (PAP_2HI(mx,mz).Flags & PAP_FLAG_NOGO)
|
|
{
|
|
MAV_turn_off_whole_square_car(mx,mz);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
//
|
|
// Look for prims that block off certain squares
|
|
//
|
|
|
|
THING_INDEX t_index;
|
|
|
|
Thing *p_thing;
|
|
t_index = PRIMARY_USED;
|
|
|
|
while(t_index)
|
|
{
|
|
p_thing = TO_THING(t_index);
|
|
|
|
if (p_thing->Class == CLASS_FURNITURE)
|
|
{
|
|
if (p_thing->Draw.Mesh->ObjectId < 5 ||
|
|
p_thing->Draw.Mesh->ObjectId == 55 ||
|
|
p_thing->Draw.Mesh->ObjectId == 40 ||
|
|
p_thing->Draw.Mesh->ObjectId == 41 ||
|
|
p_thing->Draw.Mesh->ObjectId == PRIM_OBJ_CANOPY ||
|
|
p_thing->Draw.Mesh->ObjectId == PRIM_OBJ_SIGN)
|
|
{
|
|
//
|
|
// Ignore these objects.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The rotation matrix of the prim.
|
|
//
|
|
|
|
useangle = -p_thing->Draw.Mesh->Angle;
|
|
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;
|
|
|
|
//
|
|
// Take out all squares whose centre is in the
|
|
// bounding box of the prim.
|
|
//
|
|
|
|
PrimInfo *pi = get_prim_info(p_thing->Draw.Mesh->ObjectId);
|
|
|
|
x1 = (p_thing->WorldPos.X >> 8) - pi->radius >> 8;
|
|
z1 = (p_thing->WorldPos.Z >> 8) - pi->radius >> 8;
|
|
x2 = (p_thing->WorldPos.X >> 8) + pi->radius >> 8;
|
|
z2 = (p_thing->WorldPos.Z >> 8) + pi->radius >> 8;
|
|
|
|
SATURATE(x1, 0, MAP_WIDTH - 1);
|
|
SATURATE(z1, 0, MAP_HEIGHT - 1);
|
|
SATURATE(x2, 0, MAP_WIDTH - 1);
|
|
SATURATE(z2, 0, MAP_HEIGHT - 1);
|
|
|
|
for (x = x1; x <= x2; x++)
|
|
for (z = z1; z <= z2; z++)
|
|
{
|
|
//
|
|
// Rotate the centre of the square into the space of the prim.
|
|
//
|
|
|
|
tx = ((x << 8) + 0x80) - (p_thing->WorldPos.X >> 8);
|
|
tz = ((z << 8) + 0x80) - (p_thing->WorldPos.Z >> 8);
|
|
|
|
rx = MUL64(tx, matrix[0]) + MUL64(tz, matrix[1]);
|
|
rz = MUL64(tx, matrix[2]) + MUL64(tz, matrix[3]);
|
|
|
|
#define MAV_PUSH_OUT (0x10)
|
|
|
|
if (WITHIN(rx, pi->minx - MAV_PUSH_OUT, pi->maxx + MAV_PUSH_OUT) &&
|
|
WITHIN(rz, pi->minz - MAV_PUSH_OUT, pi->maxz + MAV_PUSH_OUT))
|
|
{
|
|
//
|
|
// Turn off this square.
|
|
//
|
|
|
|
MAV_turn_off_square(x, z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
t_index = p_thing->LinkChild;
|
|
}
|
|
|
|
*/
|
|
|
|
//
|
|
// Set a bit where there is a water texture on the ground.
|
|
//
|
|
|
|
{
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG page;
|
|
|
|
for (mx = 0; mx < PAP_SIZE_HI; mx++)
|
|
for (mz = 0; mz < PAP_SIZE_HI; mz++)
|
|
{
|
|
page = PAP_2HI(mx,mz).Texture & 0x3ff;
|
|
|
|
if (page == 454 ||
|
|
page == 99456 ||
|
|
page == 99457)
|
|
{
|
|
//
|
|
// This is water texture.
|
|
//
|
|
|
|
SET_MAV_SPARE(mx,mz,MAV_SPARE_FLAG_WATER);
|
|
}
|
|
else
|
|
{
|
|
SET_MAV_SPARE(mx,mz,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MAV_draw(
|
|
SLONG sx1, SLONG sz1,
|
|
SLONG sx2, SLONG sz2)
|
|
{
|
|
SLONG i;
|
|
SLONG j;
|
|
|
|
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;
|
|
|
|
MAV_Opt *mo;
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
ULONG colour[8] =
|
|
{
|
|
0x00ff0000,
|
|
0x0000ff00,
|
|
0x000000ff,
|
|
0x00ffff00,
|
|
0x00ff00ff,
|
|
0x0000ffff,
|
|
0x00ffaa88,
|
|
0x00ffffff
|
|
};
|
|
|
|
SATURATE(sx1, 0, MAP_WIDTH - 1);
|
|
SATURATE(sz1, 0, MAP_HEIGHT - 1);
|
|
|
|
for (x = sx1; x < sx2; x++)
|
|
for (z = sz1; z < sz2; 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 = MAVHEIGHT(x,z) << 6;
|
|
y2 = MAVHEIGHT(x,z) << 6;
|
|
|
|
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.
|
|
//
|
|
|
|
if (!ControlFlag)
|
|
{
|
|
ASSERT(WITHIN(MAV_NAV(x,z), 0, MAV_opt_upto - 1));
|
|
|
|
mo = &MAV_opt[MAV_NAV(x,z)];
|
|
|
|
mx = x1 + x2 >> 1;
|
|
mz = z1 + z2 >> 1;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
dx = order[i].dx;
|
|
dz = order[i].dz;
|
|
|
|
lx = mx + dx * 96;
|
|
lz = mz + dz * 96;
|
|
|
|
lx += dz * (16 * 3);
|
|
lz += -dx * (16 * 3);
|
|
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
if (mo->opt[i] & (1 << j))
|
|
{
|
|
AENG_world_line(
|
|
mx, y1, mz, 0, 0,
|
|
lx, y2, lz, 9, colour[j],
|
|
TRUE);
|
|
}
|
|
|
|
lx += -dz * 16;
|
|
lz += +dx * 16;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mx = x1 + x2 >> 1;
|
|
mz = z1 + z2 >> 1;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
dx = order[i].dx;
|
|
dz = order[i].dz;
|
|
|
|
lx = mx + dx * 96;
|
|
lz = mz + dz * 96;
|
|
|
|
if (MAV_CAR_GOTO(x, z, i))
|
|
{
|
|
AENG_world_line(
|
|
mx, y1, mz, 0, 0,
|
|
lx, y2, lz, 9, colour[0],
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("MAV_opts_upto = %d\n", MAV_opt_upto);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// Returns TRUE if you can walk from a to b. If it returns FALSE, then
|
|
// (MAV_last_x, MAV_last_z) is the last square it reached, and (MAV_dmx, MAV_dmz)
|
|
// is the direction it tried to leave the square in.
|
|
//
|
|
|
|
SLONG MAV_last_mx;
|
|
SLONG MAV_last_mz;
|
|
SLONG MAV_dmx;
|
|
SLONG MAV_dmz;
|
|
|
|
SLONG MAV_can_i_walk(
|
|
UBYTE ax, UBYTE az,
|
|
UBYTE bx, UBYTE bz)
|
|
{
|
|
SLONG x;
|
|
SLONG z;
|
|
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
SLONG dist;
|
|
SLONG overdist;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
MAV_Opt *mo;
|
|
|
|
ASSERT(WITHIN(ax, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(az, 0, MAP_HEIGHT - 1));
|
|
|
|
ASSERT(WITHIN(bx, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(bz, 0, MAP_HEIGHT - 1));
|
|
|
|
dx = bx - ax << 4;
|
|
dz = bz - az << 4;
|
|
|
|
dist = QDIST2(abs(dx),abs(dz));
|
|
|
|
if (dist == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Normalise (dx,dz) to length 0x40 ish
|
|
//
|
|
|
|
overdist = 0x4000 / dist;
|
|
|
|
dx = dx * overdist >> 8;
|
|
dz = dz * overdist >> 8;
|
|
}
|
|
|
|
MAV_last_mx = ax;
|
|
MAV_last_mz = az;
|
|
|
|
x = (ax << 8) + 0x80;
|
|
z = (az << 8) + 0x80;
|
|
|
|
while(1)
|
|
{
|
|
x += dx;
|
|
z += dz;
|
|
|
|
mx = x >> 8;
|
|
mz = z >> 8;
|
|
|
|
MAV_dmx = mx - MAV_last_mx;
|
|
MAV_dmz = mz - MAV_last_mz;
|
|
|
|
if (MAV_dmx | MAV_dmz)
|
|
{
|
|
ASSERT(WITHIN(MAV_last_mx, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(MAV_last_mz, 0, MAP_HEIGHT - 1));
|
|
|
|
ASSERT(WITHIN(MAV_NAV(MAV_last_mx,MAV_last_mz), 0, MAV_opt_upto - 1));
|
|
|
|
mo = &MAV_opt[MAV_NAV(MAV_last_mx,MAV_last_mz)];
|
|
|
|
//
|
|
// Is there a wall in the way?
|
|
//
|
|
|
|
if (MAV_dmx == -1 && !(mo->opt[MAV_DIR_XS] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
if (MAV_dmx == +1 && !(mo->opt[MAV_DIR_XL] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
|
|
if (MAV_dmz == -1 && !(mo->opt[MAV_DIR_ZS] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
if (MAV_dmz == +1 && !(mo->opt[MAV_DIR_ZL] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
|
|
if (MAV_dmx && MAV_dmz)
|
|
{
|
|
//
|
|
// We have to try the corner pieces as well because we are moving diagonally.
|
|
//
|
|
|
|
mo = &MAV_opt[MAV_NAV(mx,MAV_last_mz)];
|
|
|
|
if (MAV_dmz == -1 && !(mo->opt[MAV_DIR_ZS] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
if (MAV_dmz == +1 && !(mo->opt[MAV_DIR_ZL] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
|
|
mo = &MAV_opt[MAV_NAV(MAV_last_mx,mz)];
|
|
|
|
if (MAV_dmx == -1 && !(mo->opt[MAV_DIR_XS] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
if (MAV_dmx == +1 && !(mo->opt[MAV_DIR_XL] & MAV_CAPS_GOTO)) {return FALSE;}
|
|
}
|
|
|
|
if (mx == bx &&
|
|
mz == bz)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
MAV_last_mx = mx;
|
|
MAV_last_mz = mz;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
UBYTE MAV_start_x;
|
|
UBYTE MAV_start_z;
|
|
|
|
UBYTE MAV_dest_x;
|
|
UBYTE MAV_dest_z;
|
|
|
|
//
|
|
// How much look-ahead we use in the navigation. MAV_node[0] is the end of
|
|
// the looked-ahead route and (MAV_node_upto - 1) is the start(x,z)
|
|
//
|
|
|
|
#define MAV_LOOKAHEAD 32
|
|
|
|
MAV_Action MAV_node[MAV_LOOKAHEAD];
|
|
SLONG MAV_node_upto;
|
|
|
|
//
|
|
// Each UBYTE is four two squares. There is three bits for action, and one bit
|
|
// to say whether we have been here or not.
|
|
//
|
|
|
|
UBYTE MAV_flag[MAP_HEIGHT][MAP_WIDTH / 2];
|
|
|
|
//
|
|
// Each UBYTE is four squares-worth of the direction
|
|
// we have come from.
|
|
//
|
|
|
|
UBYTE MAV_dir[MAP_HEIGHT][MAP_WIDTH / 4];
|
|
|
|
|
|
|
|
//
|
|
// Functions to set bits...
|
|
//
|
|
|
|
inline void MAV_visited_set(SLONG x, SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
SLONG byte = x >> 1;
|
|
SLONG bit = 8 << ((x & 0x1) << 2);
|
|
|
|
MAV_flag[z][byte] |= bit;
|
|
}
|
|
|
|
inline SLONG MAV_visited_get(SLONG x, SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
SLONG byte = x >> 1;
|
|
SLONG bit = 8 << ((x & 0x1) << 2);
|
|
|
|
return (MAV_flag[z][byte] & bit);
|
|
}
|
|
|
|
//
|
|
// This function also sets the visited flag.
|
|
//
|
|
|
|
inline void MAV_action_set(SLONG x, SLONG z, SLONG dir)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
SLONG byte = x >> 1;
|
|
SLONG shift = (x & 0x1) << 2;
|
|
|
|
dir |= 0x08; // Set the visited flag too.
|
|
|
|
MAV_flag[z][byte] &= ~(0x7 << shift);
|
|
MAV_flag[z][byte] |= (dir << shift);
|
|
}
|
|
|
|
inline SLONG MAV_action_get(SLONG x, SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
SLONG byte = x >> 1;
|
|
SLONG shift = (x & 0x1) << 2;
|
|
|
|
return ((MAV_flag[z][byte] >> shift) & 0x7);
|
|
}
|
|
|
|
inline void MAV_dir_set(SLONG x, SLONG z, SLONG dir)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
SLONG byte = x >> 2;
|
|
SLONG shift = (x & 0x3) << 1;
|
|
|
|
MAV_dir[z][byte] &= ~(0x3 << shift);
|
|
MAV_dir[z][byte] |= (dir << shift);
|
|
}
|
|
|
|
inline SLONG MAV_dir_get(SLONG x, SLONG z)
|
|
{
|
|
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
|
|
|
|
SLONG byte = x >> 2;
|
|
SLONG shift = (x & 0x3) << 1;
|
|
|
|
return ((MAV_dir[z][byte] >> shift) & 0x3);
|
|
}
|
|
|
|
//
|
|
// Clears the visited flags in given box. The
|
|
// other flags are undefined after this call.
|
|
//
|
|
|
|
void MAV_clear_bbox(
|
|
SLONG x1, SLONG z1,
|
|
SLONG x2, SLONG z2)
|
|
{
|
|
SLONG z;
|
|
SLONG len;
|
|
SLONG count;
|
|
SLONG *zero;
|
|
|
|
//
|
|
// Round x1 down and x2 up to the nearest 4 byte boundary.
|
|
//
|
|
|
|
x2 += 0x7;
|
|
x1 &= ~0x7;
|
|
x2 &= ~0x7;
|
|
|
|
SATURATE(x1, 0, MAP_WIDTH);
|
|
SATURATE(x2, 0, MAP_WIDTH);
|
|
SATURATE(z1, 0, MAP_HEIGHT);
|
|
SATURATE(z2, 0, MAP_HEIGHT);
|
|
|
|
//
|
|
// Clear a SLONG at a time.
|
|
//
|
|
|
|
len = x2 - x1 >> 3;
|
|
|
|
for (z = z1; z < z2; z++)
|
|
{
|
|
zero = (SLONG *) (&MAV_flag[z][x1 >> 1]);
|
|
count = len;
|
|
|
|
while(count--) {*zero++ = 0;}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Returns the first thing that should be done according to the current nodelist.
|
|
//
|
|
|
|
MAV_Action MAV_get_first_action_from_nodelist()
|
|
{
|
|
SLONG i;
|
|
|
|
UBYTE ax;
|
|
UBYTE az;
|
|
|
|
UBYTE bx;
|
|
UBYTE bz;
|
|
|
|
MAV_Action ans;
|
|
|
|
//
|
|
// Remember the last place we can walk to.
|
|
//
|
|
|
|
ax = MAV_start_x;
|
|
az = MAV_start_z;
|
|
|
|
ans.action = MAV_ACTION_GOTO;
|
|
ans.dest_x = ax;
|
|
ans.dest_z = az;
|
|
|
|
for (i = MAV_node_upto - 1; i >= 0; i--)
|
|
{
|
|
if (MAV_node[i].action != MAV_ACTION_GOTO)
|
|
{
|
|
ans.action = MAV_node[i].action;
|
|
ans.dir = MAV_node[i].dir;
|
|
|
|
return ans;
|
|
}
|
|
|
|
bx = MAV_node[i].dest_x;
|
|
bz = MAV_node[i].dest_z;
|
|
|
|
if (MAV_can_i_walk(
|
|
ax, az,
|
|
bx, bz))
|
|
{
|
|
ans.dest_x = bx;
|
|
ans.dest_z = bz;
|
|
}
|
|
else
|
|
{
|
|
return ans;
|
|
}
|
|
}
|
|
|
|
return ans;
|
|
}
|
|
|
|
//
|
|
// Uses the MAV_flag and MAV_dir arrays to constuct a nodelist from
|
|
// from the given position back to (start_x,start_z).
|
|
//
|
|
|
|
void MAV_create_nodelist_from_pos(UBYTE end_x, UBYTE end_z)
|
|
{
|
|
UBYTE x;
|
|
UBYTE z;
|
|
|
|
UBYTE action;
|
|
UBYTE dir;
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
x = end_x;
|
|
z = end_z;
|
|
|
|
MAV_node_upto = 0;
|
|
|
|
while(
|
|
x != MAV_start_x ||
|
|
z != MAV_start_z)
|
|
{
|
|
ASSERT(WITHIN(MAV_node_upto, 0, MAV_LOOKAHEAD - 1));
|
|
|
|
dir = MAV_dir_get(x,z);
|
|
action = MAV_action_get(x,z);
|
|
|
|
MAV_node[MAV_node_upto].dest_x = x;
|
|
MAV_node[MAV_node_upto].dest_z = z;
|
|
MAV_node[MAV_node_upto].dir = dir;
|
|
MAV_node[MAV_node_upto].action = action;
|
|
|
|
MAV_node_upto += 1;
|
|
|
|
ASSERT(WITHIN(dir, 0, 3));
|
|
|
|
x -= order[dir].dx;
|
|
z -= order[dir].dz;
|
|
|
|
if (action == MAV_ACTION_JUMP ||
|
|
action == MAV_ACTION_JUMPPULL)
|
|
{
|
|
//
|
|
// Moves you two squares.
|
|
//
|
|
|
|
x -= order[dir].dx;
|
|
z -= order[dir].dz;
|
|
}
|
|
|
|
if (action == MAV_ACTION_JUMPPULL2)
|
|
{
|
|
//
|
|
// Moves you three squares.
|
|
//
|
|
|
|
x -= order[dir].dx;
|
|
z -= order[dir].dz;
|
|
|
|
x -= order[dir].dx;
|
|
z -= order[dir].dz;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// The priority queue needs these definitions...
|
|
//
|
|
|
|
typedef struct
|
|
{
|
|
UBYTE x;
|
|
UBYTE z;
|
|
UBYTE score; // The lower the score the better...
|
|
UBYTE length;
|
|
|
|
} PQ_Type;
|
|
|
|
#define PQ_HEAP_MAX_SIZE 256
|
|
|
|
SLONG PQ_better(PQ_Type *a, PQ_Type *b)
|
|
{
|
|
return a->score < b->score;
|
|
}
|
|
|
|
#include "pq.h"
|
|
#include "pq.cpp"
|
|
|
|
|
|
//
|
|
// Returns the score associated with the given position.
|
|
//
|
|
|
|
UBYTE MAV_score_pos(UBYTE x, UBYTE z)
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
SLONG dist;
|
|
|
|
//
|
|
// Just return the distance to the destination.
|
|
//
|
|
|
|
dx = abs((MAV_dest_x - x) << 1);
|
|
dz = abs((MAV_dest_z - z) << 1);
|
|
|
|
dist = QDIST2(dx,dz);
|
|
|
|
if (dist > 255) {dist = 255;}
|
|
|
|
return dist;
|
|
}
|
|
|
|
|
|
UBYTE MAV_do_found_dest;
|
|
|
|
MAV_Action MAV_do(
|
|
SLONG me_x,
|
|
SLONG me_z,
|
|
SLONG dest_x,
|
|
SLONG dest_z,
|
|
UBYTE caps)
|
|
{
|
|
SLONG i;
|
|
SLONG j;
|
|
|
|
UBYTE opt;
|
|
UBYTE move_one;
|
|
UBYTE move_two;
|
|
UBYTE move_three;
|
|
UBYTE action;
|
|
|
|
SLONG overflows;
|
|
SLONG best_score;
|
|
MAV_Action ans;
|
|
|
|
MAV_Opt *mo;
|
|
|
|
PQ_Type start;
|
|
PQ_Type best;
|
|
PQ_Type next;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
//
|
|
// Remember the destination.
|
|
//
|
|
|
|
MAV_start_x = me_x;
|
|
MAV_start_z = me_z;
|
|
|
|
MAV_dest_x = dest_x;
|
|
MAV_dest_z = dest_z;
|
|
|
|
//
|
|
// Clear the flag by default.
|
|
//
|
|
|
|
MAV_do_found_dest = FALSE;
|
|
|
|
//
|
|
// Clear the flags.
|
|
//
|
|
|
|
MAV_clear_bbox(
|
|
me_x - MAV_LOOKAHEAD,
|
|
me_z - MAV_LOOKAHEAD,
|
|
me_x + MAV_LOOKAHEAD,
|
|
me_z + MAV_LOOKAHEAD);
|
|
|
|
//memset(MAV_flag, 0, sizeof(MAV_flag));
|
|
|
|
//
|
|
// Initialise the heap with our start square.
|
|
//
|
|
|
|
PQ_init();
|
|
|
|
start.x = me_x;
|
|
start.z = me_z;
|
|
start.score = MAV_score_pos(me_x, me_z);
|
|
start.length = 0;
|
|
|
|
PQ_add(start);
|
|
|
|
MAV_visited_set(me_x,me_z);
|
|
|
|
//
|
|
// Initialise the score and answer.
|
|
//
|
|
|
|
#define MAV_MAX_OVERFLOWS 8
|
|
|
|
overflows = 0;
|
|
best_score = INFINITY;
|
|
ans.action = MAV_ACTION_GOTO;
|
|
ans.dir = 0;
|
|
ans.dest_x = me_x;
|
|
ans.dest_z = me_z;
|
|
|
|
while(1)
|
|
{
|
|
if (PQ_empty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the best square so far and move it on a bit.
|
|
//
|
|
|
|
best = PQ_best();
|
|
PQ_remove();
|
|
|
|
if (best.length >= MAV_LOOKAHEAD)
|
|
{
|
|
if (best.score < best_score)
|
|
{
|
|
best_score = best.score;
|
|
|
|
//
|
|
// Work out the first action and put it in answer.
|
|
//
|
|
|
|
MAV_create_nodelist_from_pos(best.x, best.z);
|
|
ans = MAV_get_first_action_from_nodelist();
|
|
}
|
|
|
|
overflows += 1;
|
|
|
|
if (overflows >= MAV_MAX_OVERFLOWS)
|
|
{
|
|
//
|
|
// Dont do any more calculation.
|
|
//
|
|
|
|
return ans;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (best.x == MAV_dest_x &&
|
|
best.z == MAV_dest_z)
|
|
{
|
|
//
|
|
// Found the destination.
|
|
//
|
|
|
|
MAV_do_found_dest = TRUE;
|
|
|
|
//
|
|
// Work out the first action and return it as the answer.
|
|
//
|
|
|
|
MAV_create_nodelist_from_pos(best.x, best.z);
|
|
ans = MAV_get_first_action_from_nodelist();
|
|
|
|
return ans;
|
|
}
|
|
|
|
ASSERT(WITHIN(best.x, 0, MAP_WIDTH - 1));
|
|
ASSERT(WITHIN(best.z, 0, MAP_HEIGHT - 1));
|
|
|
|
ASSERT(WITHIN(MAV_NAV(best.x,best.z), 0, MAV_opt_upto - 1));
|
|
|
|
mo = &MAV_opt[MAV_NAV(best.x,best.z)];
|
|
|
|
//
|
|
// Add neighbouring squares to the priority queue.
|
|
//
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
opt = mo->opt[i] & caps;
|
|
|
|
//
|
|
// Moving one square.
|
|
//
|
|
|
|
move_one = opt & (MAV_CAPS_GOTO | MAV_CAPS_PULLUP | MAV_CAPS_CLIMB_OVER | MAV_CAPS_FALL_OFF | MAV_CAPS_LADDER_UP);
|
|
move_two = opt & (MAV_CAPS_JUMP | MAV_CAPS_JUMPPULL);
|
|
move_three = opt & (MAV_CAPS_JUMPPULL2);
|
|
|
|
dx = order[i].dx;
|
|
dz = order[i].dz;
|
|
|
|
if (move_one)
|
|
{
|
|
mx = best.x + dx;
|
|
mz = best.z + dz;
|
|
|
|
if (!MAV_visited_get(mx,mz))
|
|
{
|
|
next.x = mx;
|
|
next.z = mz;
|
|
next.length = best.length + 1;
|
|
next.score = MAV_score_pos(mx,mz);
|
|
|
|
//
|
|
// What action did we use to get here?
|
|
//
|
|
|
|
if (opt & MAV_CAPS_GOTO) {action = MAV_ACTION_GOTO;}
|
|
else if (opt & MAV_CAPS_PULLUP) {action = MAV_ACTION_PULLUP;}
|
|
else if (opt & MAV_CAPS_CLIMB_OVER) {action = MAV_ACTION_CLIMB_OVER;}
|
|
else if (opt & MAV_CAPS_FALL_OFF) {action = MAV_ACTION_FALL_OFF;}
|
|
else if (opt & MAV_CAPS_LADDER_UP) {action = MAV_ACTION_LADDER_UP;}
|
|
else ASSERT(0);
|
|
|
|
//
|
|
// How we reached this square.
|
|
//
|
|
|
|
MAV_action_set( // Sets the visited flag aswell.
|
|
mx,
|
|
mz,
|
|
action);
|
|
|
|
MAV_dir_set(
|
|
mx,
|
|
mz,
|
|
i);
|
|
|
|
if (action != MAV_ACTION_GOTO)
|
|
{
|
|
//
|
|
// Bias against using strange methods of travel!
|
|
//
|
|
|
|
next.score += Random() & 0x3;
|
|
|
|
if (action == MAV_ACTION_FALL_OFF)
|
|
{
|
|
//
|
|
// Falling off isn't so bad...
|
|
//
|
|
}
|
|
else
|
|
{
|
|
next.score += 3;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add this square to the priority queue.
|
|
//
|
|
|
|
PQ_add(next);
|
|
}
|
|
}
|
|
|
|
if (move_two)
|
|
{
|
|
mx = best.x + dx + dx;
|
|
mz = best.z + dz + dz;
|
|
|
|
if (!MAV_visited_get(mx,mz))
|
|
{
|
|
next.x = mx;
|
|
next.z = mz;
|
|
next.length = best.length + 1;
|
|
next.score = MAV_score_pos(mx,mz);
|
|
|
|
//
|
|
// What action did we use to get here?
|
|
//
|
|
|
|
if (opt & MAV_CAPS_JUMP) {action = MAV_ACTION_JUMP;}
|
|
else if (opt & MAV_CAPS_JUMPPULL) {action = MAV_ACTION_JUMPPULL;}
|
|
else ASSERT(0);
|
|
|
|
//
|
|
// How we reached this square.
|
|
//
|
|
|
|
MAV_action_set( // Sets the visited flag aswell.
|
|
mx,
|
|
mz,
|
|
action);
|
|
|
|
MAV_dir_set(
|
|
mx,
|
|
mz,
|
|
i);
|
|
|
|
//
|
|
// Add this square to the priority queue.
|
|
//
|
|
|
|
PQ_add(next);
|
|
}
|
|
}
|
|
|
|
if (move_three)
|
|
{
|
|
mx = best.x + dx + dx + dx;
|
|
mz = best.z + dz + dz + dz;
|
|
|
|
if (!MAV_visited_get(mx,mz))
|
|
{
|
|
next.x = mx;
|
|
next.z = mz;
|
|
next.length = best.length + 1;
|
|
next.score = MAV_score_pos(mx,mz);
|
|
|
|
//
|
|
// What action did we use to get here?
|
|
//
|
|
|
|
action = MAV_ACTION_JUMPPULL2;
|
|
|
|
//
|
|
// How we reached this square.
|
|
//
|
|
|
|
MAV_action_set( // Sets the visited flag aswell.
|
|
mx,
|
|
mz,
|
|
action);
|
|
|
|
MAV_dir_set(
|
|
mx,
|
|
mz,
|
|
i);
|
|
|
|
//
|
|
// Add this square to the priority queue.
|
|
//
|
|
|
|
PQ_add(next);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ans;
|
|
}
|
|
|
|
|
|
|
|
SLONG MAV_inside(
|
|
SLONG x,
|
|
SLONG y,
|
|
SLONG z)
|
|
{
|
|
x >>= 8;
|
|
y >>= 6;
|
|
z >>= 8;
|
|
|
|
if (WITHIN(x, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(z, 0, MAP_HEIGHT - 1))
|
|
{
|
|
if (y < -127) {return TRUE;}
|
|
if (y > +127) {return FALSE;}
|
|
|
|
if (y < MAVHEIGHT(x,z))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
SLONG MAV_height_los_fail_x;
|
|
SLONG MAV_height_los_fail_y;
|
|
SLONG MAV_height_los_fail_z;
|
|
|
|
SLONG MAV_height_los_fast(
|
|
SLONG x1, SLONG y1, SLONG z1,
|
|
SLONG x2, SLONG y2, SLONG z2)
|
|
{
|
|
SLONG dx = x2 - x1;
|
|
SLONG dy = y2 - y1;
|
|
SLONG dz = z2 - z1;
|
|
|
|
SLONG dist = QDIST2(abs(dx),abs(dz));
|
|
SLONG steps = (dist >> 8) + 1;
|
|
|
|
SLONG x = x1;
|
|
SLONG y = y1;
|
|
SLONG z = z1;
|
|
|
|
dx /= steps;
|
|
dy /= steps;
|
|
dz /= steps;
|
|
|
|
while(steps-- >= 0)
|
|
{
|
|
if (MAV_inside(x,y,z))
|
|
{
|
|
MAV_height_los_fail_x = x - (dx >> 0);
|
|
MAV_height_los_fail_y = y - (dy >> 0);
|
|
MAV_height_los_fail_z = z - (dz >> 0);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
x += dx;
|
|
y += dy;
|
|
z += dz;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SLONG MAV_height_los_slow(
|
|
SLONG ware,
|
|
SLONG x1, SLONG y1, SLONG z1,
|
|
SLONG x2, SLONG y2, SLONG z2)
|
|
{
|
|
SLONG dx = x2 - x1;
|
|
SLONG dy = y2 - y1;
|
|
SLONG dz = z2 - z1;
|
|
|
|
SLONG dist = QDIST2(abs(dx),abs(dz));
|
|
SLONG steps = (dist >> 8) + 1;
|
|
|
|
dx /= steps;
|
|
dy /= steps;
|
|
dz /= steps;
|
|
|
|
SLONG x = x1 + dx;
|
|
SLONG y = y1 + dy;
|
|
SLONG z = z1 + dz;
|
|
|
|
while(steps-- > 0)
|
|
{
|
|
SLONG inside;
|
|
|
|
if (ware)
|
|
{
|
|
inside = WARE_inside(ware, x, y, z);
|
|
}
|
|
else
|
|
{
|
|
inside = MAV_inside(x,y,z);
|
|
}
|
|
|
|
if (inside)
|
|
{
|
|
MAV_height_los_fail_x = x;
|
|
MAV_height_los_fail_y = y;
|
|
MAV_height_los_fail_z = z;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
x += dx;
|
|
y += dy;
|
|
z += dz;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Finds the nearest building entrance to the given place. Returns
|
|
// FALSE if the building doesn't have an entrance.
|
|
//
|
|
|
|
#ifdef UNUSED
|
|
SLONG MAV_find_building_entrance(
|
|
SLONG building,
|
|
SLONG near_to_x,
|
|
SLONG near_to_y,
|
|
SLONG near_to_z,
|
|
SLONG *door_x,
|
|
SLONG *door_z)
|
|
{
|
|
SLONG facet;
|
|
SLONG score;
|
|
SLONG x1;
|
|
SLONG z1;
|
|
SLONG x2;
|
|
SLONG z2;
|
|
SLONG dx;
|
|
SLONG dz;
|
|
SLONG goto_x;
|
|
SLONG goto_z;
|
|
SLONG best_x;
|
|
SLONG best_z;
|
|
SLONG best_score;
|
|
|
|
DBuilding *db = &dbuildings[building];
|
|
DFacet *df;
|
|
|
|
best_x = 0;
|
|
best_z = 0;
|
|
best_score = INFINITY;
|
|
|
|
//
|
|
// 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;
|
|
|
|
goto_x = x1 + dx - dz;
|
|
goto_z = z1 + dz + dx;
|
|
|
|
//
|
|
// How far is this door?
|
|
//
|
|
|
|
dx = near_to_x - goto_x;
|
|
dz = near_to_z - goto_z;
|
|
|
|
score = abs(dx) + abs(dz);
|
|
|
|
//
|
|
// Nearest door so far?
|
|
//
|
|
|
|
if (best_score > score)
|
|
{
|
|
best_score = score;
|
|
best_x = goto_x;
|
|
best_z = goto_z;
|
|
}
|
|
}
|
|
}
|
|
|
|
*door_x = best_x >> 8;
|
|
*door_z = best_z >> 8;
|
|
|
|
return best_score != INFINITY;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifndef PSX
|
|
void MAV_precalculate_warehouse_nav(UBYTE ware)
|
|
{
|
|
SLONG i;
|
|
|
|
SLONG x;
|
|
SLONG y;
|
|
SLONG z;
|
|
|
|
SLONG x1;
|
|
SLONG y1;
|
|
SLONG z1;
|
|
|
|
SLONG x2;
|
|
SLONG y2;
|
|
SLONG z2;
|
|
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
SLONG mx;
|
|
SLONG mz;
|
|
|
|
SLONG tx;
|
|
SLONG tz;
|
|
|
|
SLONG rx;
|
|
SLONG rz;
|
|
|
|
SLONG dh;
|
|
|
|
SLONG useangle;
|
|
SLONG matrix[4];
|
|
SLONG ladder;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
SLONG both_ground;
|
|
|
|
struct
|
|
{
|
|
SLONG dx;
|
|
SLONG dz;
|
|
|
|
} order[4] =
|
|
{
|
|
{-1, 0},
|
|
{+1, 0},
|
|
{0, -1},
|
|
{0, +1}
|
|
};
|
|
|
|
UBYTE opt[4];
|
|
|
|
WARE_Ware *ww = &WARE_ware[ware];
|
|
|
|
//
|
|
// Remember the old MAV_nav array.
|
|
//
|
|
|
|
UWORD *old_mav_nav = MAV_nav;
|
|
SLONG old_mav_nav_pitch = MAV_nav_pitch;
|
|
|
|
//
|
|
// Set the MAV_nav array to point to the warehouse's private array.
|
|
//
|
|
|
|
MAV_nav = &WARE_nav[ww->nav];
|
|
MAV_nav_pitch = ww->nav_pitch;
|
|
|
|
//
|
|
// Make the staircase prims change the MAV_height array
|
|
//
|
|
|
|
OB_Info *oi;
|
|
|
|
for (x = 0; x < PAP_SIZE_LO; x++)
|
|
for (z = 0; z < PAP_SIZE_LO; z++)
|
|
{
|
|
for (oi = OB_find(x,z); oi->prim; oi++)
|
|
{
|
|
if (oi->prim == 41)
|
|
{
|
|
//
|
|
// The step prim!
|
|
//
|
|
|
|
//
|
|
// Find which mapsquare the middle of this prim is over.
|
|
//
|
|
|
|
PrimInfo *pi = get_prim_info(oi->prim);
|
|
|
|
SLONG mx = pi->minx + pi->maxx >> 1;
|
|
SLONG mz = pi->minz + pi->maxz >> 1;
|
|
|
|
SLONG matrix[4];
|
|
SLONG useangle;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
SLONG rx;
|
|
SLONG rz;
|
|
|
|
SLONG sx;
|
|
SLONG sz;
|
|
|
|
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(mx, matrix[0]) + MUL64(mz, matrix[1]);
|
|
rz = MUL64(mx, matrix[2]) + MUL64(mz, matrix[3]);
|
|
|
|
rx += oi->x;
|
|
rz += oi->z;
|
|
|
|
rx >>= 8;
|
|
rz >>= 8;
|
|
|
|
if (WITHIN(rx, ww->minx, ww->maxx) &&
|
|
WITHIN(rz, ww->minz, ww->maxz))
|
|
{
|
|
MAVHEIGHT(rx,rz) = oi->y + 0x40 >> 6;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Work out the mav for each square in the bounding box of the warehouse.
|
|
//
|
|
|
|
for (x = ww->minx; x <= ww->maxx; x++)
|
|
for (z = ww->minz; z <= ww->maxz; z++)
|
|
{
|
|
mx = x - ww->minx;
|
|
mz = z - ww->minz;
|
|
|
|
//
|
|
// Look for a nearby ladder.
|
|
//
|
|
|
|
ladder = find_nearby_ladder_colvect_radius(
|
|
(x << 8) + 0x80,
|
|
(z << 8) + 0x80,
|
|
0x100);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
opt[i] = 0;
|
|
|
|
dx = order[i].dx;
|
|
dz = order[i].dz;
|
|
|
|
tx = x + dx;
|
|
tz = z + dz;
|
|
|
|
if (!(PAP_2HI(x,z).Flags & PAP_FLAG_HIDDEN))
|
|
{
|
|
//
|
|
// This square is outside the warehouse.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!WITHIN(tx, ww->minx, ww->maxx) ||
|
|
!WITHIN(tz, ww->minz, ww->maxz))
|
|
{
|
|
//
|
|
// Cannot navigate in this direction because it is
|
|
// outside the warehouse.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!(PAP_2HI(tx,tz).Flags & PAP_FLAG_HIDDEN))
|
|
{
|
|
//
|
|
// This square is outside the warehouse.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Can we walk from (x,z) to (tx,tz)?
|
|
//
|
|
|
|
dh = MAVHEIGHT(tx,tz) - MAVHEIGHT(x,z);
|
|
|
|
if (abs(dh) > 1)
|
|
{
|
|
//
|
|
// There are at different heights, so you cant
|
|
// just walk between the two squares.
|
|
//
|
|
|
|
if (dh < 0)
|
|
{
|
|
//
|
|
// There might be a wall or fence in the way.
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = (MAVHEIGHT( x, z) << 6) + 0x50;
|
|
y2 = (MAVHEIGHT(tx,tz) << 6) + 0x50;
|
|
|
|
y = MAX(y1,y2);
|
|
|
|
if (there_is_a_los(
|
|
x1, y, z1,
|
|
x2, y, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
//
|
|
// We can always fall down becuase there is nothing in the way.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_FALL_OFF;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If there is a fence in the way, then we can scale the fence.
|
|
//
|
|
|
|
DFacet *df = &dfacets[los_failure_dfacet];
|
|
|
|
if (df->FacetType == STOREY_TYPE_FENCE_FLAT)
|
|
{
|
|
if (df->FacetFlags & FACET_FLAG_UNCLIMBABLE)
|
|
{
|
|
//
|
|
// Unclimbable fence.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can scale this fence.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_CLIMB_OVER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (WITHIN(dh, 3, 5))
|
|
{
|
|
//
|
|
// We can pull ourselves up.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_PULLUP;
|
|
}
|
|
|
|
if (ladder)
|
|
{
|
|
DFacet *df_ladder;
|
|
|
|
ASSERT(WITHIN(ladder, 1, next_dfacet - 1));
|
|
|
|
df_ladder = &dfacets[ladder];
|
|
|
|
ASSERT(df_ladder->FacetType == STOREY_TYPE_LADDER);
|
|
|
|
//
|
|
// There is a ladder- can we climb up it in this direction?
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
if (two4_line_intersection(
|
|
x1, z1,
|
|
x2, z2,
|
|
df_ladder->x[0] << 8, df_ladder->z[0] << 8,
|
|
df_ladder->x[1] << 8, df_ladder->z[1] << 8))
|
|
{
|
|
opt[i] |= MAV_CAPS_LADDER_UP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There might be a wall or fence in the way.
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = (MAVHEIGHT( x, z) << 6) + 0x50;
|
|
y2 = (MAVHEIGHT(tx,tz) << 6) + 0x50;
|
|
|
|
y = MAX(y1,y2);
|
|
|
|
if (there_is_a_los(
|
|
x1, y, z1,
|
|
x2, y, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
//
|
|
// Nothing in the way...
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_GOTO;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If there is a fence in the way, then we can scale the fence.
|
|
//
|
|
|
|
DFacet *df = &dfacets[los_failure_dfacet];
|
|
|
|
if (df->FacetType == STOREY_TYPE_FENCE_FLAT)
|
|
{
|
|
if (df->FacetFlags & FACET_FLAG_UNCLIMBABLE)
|
|
{
|
|
//
|
|
// Unclimbable fence.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can scale this fence.
|
|
//
|
|
|
|
opt[i] |= MAV_CAPS_CLIMB_OVER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(opt[i] & MAV_CAPS_GOTO) &&
|
|
!(opt[i] & MAV_CAPS_CLIMB_OVER))
|
|
{
|
|
//
|
|
// Now what about jumping one block?
|
|
//
|
|
|
|
tx += dx;
|
|
tz += dz;
|
|
|
|
if (WITHIN(tx, ww->minx, ww->maxx) &&
|
|
WITHIN(tz, ww->minz, ww->maxz) &&
|
|
(PAP_2HI(tx,tz).Flags & PAP_FLAG_HIDDEN))
|
|
{
|
|
dh = MAVHEIGHT(tx,tz) - MAVHEIGHT(x,z);
|
|
|
|
//
|
|
// Can we jump there?
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = (MAVHEIGHT( x, z) << 6) + 0xa0;
|
|
y2 = (MAVHEIGHT(tx,tz) << 6) + 0xa0;
|
|
|
|
if (there_is_a_los(
|
|
x1, y1, z1,
|
|
x2, y2, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
if (dh < 2)
|
|
{
|
|
opt[i] |= MAV_CAPS_JUMP;
|
|
}
|
|
else
|
|
{
|
|
if (WITHIN(dh, 2, 5))
|
|
{
|
|
opt[i] |= MAV_CAPS_JUMPPULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// What about jumping two blocks?
|
|
//
|
|
|
|
tx += dx;
|
|
tz += dz;
|
|
|
|
if (WITHIN(tx, 0, MAP_WIDTH - 1) &&
|
|
WITHIN(tz, 0, MAP_HEIGHT - 1))
|
|
{
|
|
dh = MAVHEIGHT(tx,tz) - MAVHEIGHT(x,z);
|
|
|
|
if (dh > 4)
|
|
{
|
|
//
|
|
// Can't make this jump
|
|
//
|
|
}
|
|
else
|
|
{
|
|
if (dh > -6)
|
|
{
|
|
//
|
|
// Can we jump there?
|
|
//
|
|
|
|
x1 = ( x << 8) + 0x80;
|
|
z1 = ( z << 8) + 0x80;
|
|
x2 = (tx << 8) + 0x80;
|
|
z2 = (tz << 8) + 0x80;
|
|
|
|
y1 = (MAVHEIGHT( x, z) << 6) + 0xa0;
|
|
y2 = (MAVHEIGHT(tx,tz) << 6) + 0xa0;
|
|
|
|
if (there_is_a_los(
|
|
x1, y1, z1,
|
|
x2, y2, z2,
|
|
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG))
|
|
{
|
|
opt[i] |= MAV_CAPS_JUMPPULL2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
StoreMavOpts(mx, mz, opt);
|
|
}
|
|
|
|
//
|
|
// A hack for the staircase prim.
|
|
//
|
|
|
|
for (x = 0; x < PAP_SIZE_LO; x++)
|
|
for (z = 0; z < PAP_SIZE_LO; z++)
|
|
{
|
|
for (oi = OB_find(x,z); oi->prim; oi++)
|
|
{
|
|
if (oi->prim == 41)
|
|
{
|
|
//
|
|
// The step prim!
|
|
//
|
|
|
|
{
|
|
//
|
|
// Find which mapsquare the middle of this prim is over.
|
|
//
|
|
|
|
PrimInfo *pi = get_prim_info(oi->prim);
|
|
|
|
SLONG mx = pi->minx + pi->maxx >> 1;
|
|
SLONG mz = pi->minz + pi->maxz >> 1;
|
|
|
|
SLONG matrix[4];
|
|
SLONG useangle;
|
|
|
|
SLONG sin_yaw;
|
|
SLONG cos_yaw;
|
|
|
|
SLONG rx;
|
|
SLONG rz;
|
|
|
|
SLONG sx;
|
|
SLONG sz;
|
|
|
|
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(mx, matrix[0]) + MUL64(mz, matrix[1]);
|
|
rz = MUL64(mx, matrix[2]) + MUL64(mz, matrix[3]);
|
|
|
|
rx += oi->x;
|
|
rz += oi->z;
|
|
|
|
rx >>= 8;
|
|
rz >>= 8;
|
|
|
|
if (WITHIN(rx, ww->minx, ww->maxx) &&
|
|
WITHIN(rz, ww->minz, ww->maxz))
|
|
{
|
|
mx = rx - ww->minx;
|
|
mz = rz - ww->minz;
|
|
|
|
if (oi->yaw < 256 || oi->yaw > 1792 || WITHIN(oi->yaw, 768, 1280))
|
|
{
|
|
if (MAVHEIGHT(rx,rz) == MAVHEIGHT(rx-1,rz))
|
|
{
|
|
//
|
|
// Walking left-right on a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(mx, mz, MAV_DIR_XS);
|
|
MAV_turn_movement_off(mx - 1, mz, MAV_DIR_XL);
|
|
}
|
|
|
|
if (MAVHEIGHT(rx,rz) == MAVHEIGHT(rx+1,rz))
|
|
{
|
|
//
|
|
// Walking left-right on a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(mx, mz, MAV_DIR_XL);
|
|
MAV_turn_movement_off(mx + 1, mz, MAV_DIR_XS);
|
|
}
|
|
|
|
if (!WITHIN(oi->yaw, 768, 1280))
|
|
{
|
|
if (MAVHEIGHT(rx,rz+1) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(mx,mz, MAV_DIR_ZL);
|
|
MAV_turn_movement_on(mx,mz+1, MAV_DIR_ZS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MAVHEIGHT(rx,rz-1) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(mx,mz, MAV_DIR_ZS);
|
|
MAV_turn_movement_on(mx,mz-1, MAV_DIR_ZL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MAVHEIGHT(rx, rz) == MAVHEIGHT(rx, rz-1))
|
|
{
|
|
//
|
|
// Walking across a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(mx, mz, MAV_DIR_ZS);
|
|
MAV_turn_movement_off(mx, mz - 1, MAV_DIR_ZL);
|
|
}
|
|
|
|
if (MAVHEIGHT(rx, rz) == MAVHEIGHT(rx, rz+1))
|
|
{
|
|
//
|
|
// Walking across a wide staircase.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
MAV_turn_movement_off(mx, mz, MAV_DIR_ZL);
|
|
MAV_turn_movement_off(mx, mz + 1, MAV_DIR_ZS);
|
|
}
|
|
|
|
if (!WITHIN(oi->yaw, 256, 768))
|
|
{
|
|
if (MAVHEIGHT(rx-1,rz) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(mx, mz, MAV_DIR_XS);
|
|
MAV_turn_movement_on(mx-1,mz, MAV_DIR_XL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MAVHEIGHT(rx+1,rz) <= MAVHEIGHT(rx,rz) + 3)
|
|
{
|
|
MAV_turn_movement_on(mx, mz, MAV_DIR_XL);
|
|
MAV_turn_movement_on(mx+1, mz, MAV_DIR_XS);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore the old MAV_nav array.
|
|
//
|
|
|
|
MAV_nav = old_mav_nav;
|
|
MAV_nav_pitch = old_mav_nav_pitch;
|
|
}
|
|
#endif
|
|
|
|
|
|
UBYTE MAV_get_caps(
|
|
UBYTE x,
|
|
UBYTE z,
|
|
UBYTE dir)
|
|
{
|
|
UBYTE ans;
|
|
|
|
MAV_Opt *mo;
|
|
|
|
if (WITHIN(x, 0, MAV_nav_pitch - 1) &&
|
|
WITHIN(z, 0, MAV_nav_pitch - 1))
|
|
{
|
|
mo = &MAV_opt[MAV_NAV(x,z)];
|
|
|
|
ASSERT(WITHIN(dir, 0, 3));
|
|
|
|
ans = mo->opt[dir];
|
|
|
|
return ans;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void MAV_turn_car_movement_on(UBYTE mx, UBYTE mz, UBYTE dir)
|
|
{
|
|
UBYTE mav;
|
|
|
|
ASSERT(WITHIN(mx, 0, PAP_SIZE_HI - 1));
|
|
ASSERT(WITHIN(mz, 0, PAP_SIZE_HI - 1));
|
|
|
|
mav = MAV_CAR(mx,mz);
|
|
mav |= 1 << dir;
|
|
|
|
SET_MAV_CAR(mx,mz,mav);
|
|
}
|
|
|
|
void MAV_turn_car_movement_off(UBYTE mx, UBYTE mz, UBYTE dir)
|
|
{
|
|
UBYTE mav;
|
|
|
|
ASSERT(WITHIN(mx, 0, PAP_SIZE_HI - 1));
|
|
ASSERT(WITHIN(mz, 0, PAP_SIZE_HI - 1));
|
|
|
|
mav = MAV_CAR(mx,mz);
|
|
mav &= ~(1 << dir);
|
|
|
|
SET_MAV_CAR(mx,mz,mav);
|
|
}
|
|
|