scummvm/engines/icb/barriers.cpp
2021-12-26 21:19:38 +01:00

1470 lines
52 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/icb/p4.h"
#include "engines/icb/common/px_common.h"
#include "engines/icb/common/px_floor_map.h"
#include "engines/icb/common/px_linkeddatafile.h"
#include "engines/icb/common/px_route_barriers.h"
#include "engines/icb/common/px_prop_anims.h"
#include "engines/icb/mission.h"
#include "engines/icb/session.h"
#include "engines/icb/debug.h"
#include "engines/icb/floors.h"
#include "engines/icb/barriers.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/res_man.h"
#include "common/textconsole.h"
namespace ICB {
// how much you get nudge along a nudge barrier per cycle
#define NUDGE_DISTANCE (10)
// How close you have to get to barriers to consider a collision
// Note : the run anim has a delta movement of 30cm hence the 35cm figure
#define BARRIER_CLOSE (20 * FLOAT_ONE)
#define RUN_BARRIER_CLOSE (35 * FLOAT_ONE)
// Only do fort-knox solution on barriers closer than this distance
#define IGNORE_BARRIER_CLOSE (100 * FLOAT_ONE)
// made bigger than barrier close so we hit stairs before atual barriers that surround them
#define STAIR_CLOSE 25 * FLOAT_ONE
#define LADDER_TOP_CLOSE 50 * FLOAT_ONE
// Ignore barriers that are more than this away from players height
#define BARRIER_TOO_HIGH (100 * REAL_ONE)
// above this angle the mega is blocked, below this angle it is aligned
#define BARRIER_TOLERANCE ((FULL_TURN * 70) / 360) // 70 deg
// For Sony testing make these variables for altering at run-time
// in long term they will become constants
// How much you get reflected away from a barrier when you are aligned with it
PXreal REPEL_TURN = ((FULL_TURN * 6) / 360); // 6 deg
// how much you get repulsed away from a barrier per cycle when you
// are being aligned with it
PXreal REPULSE_DISTANCE = (15 * REAL_ONE); // 15 cm
__barrier_result _game_session::Check_barrier_bump_and_bounce(PXreal newx, PXreal newy, PXreal newz, PXreal oldx, PXreal /* oldy */, PXreal oldz, bool8 pl) {
// see if the coordinates passed are close to the players current barriers
// returns 0 no barrier found thats too near
// 1 a barrier was too close
_route_barrier *bar;
PXreal pdist, dist;
uint32 j;
PXfloat barrier_tolerance = BARRIER_TOLERANCE; // 1/8 of a turn = 45 degress
PXfloat diff;
int32 ignoreThis;
// 1 = means don't do fort knox solution on this barrier
// 0 = means do fort knox solution on this barrier
int32 ignoreBarrier[MAX_barriers];
PXreal bar_close = BARRIER_CLOSE; // changes if player running or walking
if (pl) {
// is player running
if (Get_motion() == __MOTION_RUN) // running
bar_close = RUN_BARRIER_CLOSE;
// check for stair entry complience - oh yes
for (j = 0; j < num_stairs; j++) {
bar = &stairs[j].bar;
// blocked if stair/ladder is disabled
if (!stairs[j].live)
continue;
if (newy != bar->bottom())
continue; // not on our floor so continue with next
pdist = ((newx * bar->bcm().lpx()) + (newz * bar->bcm().lpz())) - bar->bcm().linedist();
if (((PXfloat)PXfabs(pdist) < STAIR_CLOSE) || // stair
((!stairs[j].is_stair) && (!stairs[j].up) && ((PXfloat)PXfabs(pdist) < LADDER_TOP_CLOSE))) { // top of stairs
// we are near the plane so now we must check the end points
// check the left end of the line
dist = ((newx * bar->bcm().alpx()) + (newz * bar->bcm().alpz())) - bar->bcm().alinedist();
// check the right end
if (dist >= 0) {
dist = ((newx * bar->bcm().blpx()) + (newz * bar->bcm().blpz())) - bar->bcm().blinedist();
if (dist >= 0) {
// ok, its a hit
// we need to crash into the barrier if we're crouched
if (M->Is_crouched())
return __BLOCKED;
// and crash if we're armed
if (M->Fetch_armed_status())
return __BLOCKED;
// must be walking or running upright - so off we go
diff = L->pan - stairs[j].pan;
// correct
if (diff > HALF_TURN)
diff -= FULL_TURN;
else if (diff < -HALF_TURN)
diff += FULL_TURN;
if (PXfabs(diff) < (FULL_TURN / 10)) { // 36 deg = +/- 18 deg
L->pan = stairs[j].pan;
MS->player.stair_num = (uint8)j; // actual stair index number
MS->player.stair_unit = 0; // units into cycle
MS->player.stair_dir = stairs[j].up; // 1 is up, 0 is down
MS->player.begun_at_bottom = stairs[j].up; // 1 is started at bottom
MS->player.was_climbing = FALSE8; // no y movement into the cycle
if (stairs[j].is_stair) { // stair or ladder
M->on_stairs = TRUE8; // for shadow correction system
// stairs
if (Get_motion() == __MOTION_RUN) // running
MS->player.Set_player_status(RUNNING_ON_STAIRS);
else
MS->player.Set_player_status(ON_STAIRS);
if (MS->player.stair_dir) // going up
MS->player.step_sample_num = 0; // starting at bottom so sampling starts at 0
else
MS->player.step_sample_num = TOP_stair_num; // starting at top
// set the stairway coordinate correction system
for (uint32 k = 0; k < MAX_stair_length; k++)
MS->player.step_samples[k].stepped_on_step = FALSE8;
} else { // ladder
MS->player.left_right = 0;
if (MS->player.stair_dir) { // going up
#define SNAP_BACK_DOWN 70
#define SNAP_BACK_UP 25
Snap_to_ladder(&stairs[j], SNAP_BACK_UP);
MS->player.was_climbing = TRUE8; // into anim has movement
MS->player.Easy_start_new_mode(ON_LADDER, __CORD_STAND_TO_CLIMB_UP_LADDER);
} else {
M->drawShadow = FALSE8; // shadows off
Snap_to_ladder(&stairs[j], SNAP_BACK_DOWN);
camera_lock = TRUE8; // stop rough room cut through effect
MS->player.Easy_start_new_mode(BEGIN_DOWN_LADDER, __STAND_TO_CLIMB_DOWN_LADDER_RIGHT);
}
return (__NUDGED);
}
return (__OK);
}
}
}
}
}
// check for collision with nudge barriers
for (j = 0; j < M->number_of_nudge; j++) {
int32 b = Fetch_megas_nudge_barrier_number(j);
bar = session_barriers->Fetch_barrier(b);
pdist = ((newx * bar->bcm().lpx()) + (newz * bar->bcm().lpz())) - bar->bcm().linedist();
if ((PXfloat)PXfabs(pdist) < BARRIER_CLOSE) {
// we are near the plane so now we must check the end points
// check the left end of the line
dist = ((newx * bar->bcm().alpx()) + (newz * bar->bcm().alpz())) - bar->bcm().alinedist();
// check the right end
// Make barrier a bit longer to nudge player through the doorway nicely
if (dist > -bar_close) {
dist = ((newx * bar->bcm().blpx()) + (newz * bar->bcm().blpz())) - bar->bcm().blinedist();
// Make barrier a bit longer to nudge player through the doorway nicely
if (dist > -bar_close) {
// check angle - narrow ones are ignored
PXfloat delta = remainder(L->pan - bar->pan(), FULL_TURN, HALF_TURN);
PXfloat delta2 = delta;
if (delta < -QUARTER_TURN)
delta2 += HALF_TURN;
if (delta > QUARTER_TURN)
delta2 -= HALF_TURN;
PXfloat fd = (PXfloat)PXfabs(delta2);
if (fd >= barrier_tolerance) {
// ok, we are close to the barrier and at an acceptable angle - now nudge along
// work out pan of barrier
// we have our coordinate and a direction to shift in
PXfloat ang = bar->pan() * TWO_PI;
PXfloat cang = (PXfloat)PXcos(ang);
PXfloat sang = (PXfloat)PXsin(ang);
// Let's ignore the zero*something as it is always zero
M->actor_xyz.x += PXfloat2PXreal(NUDGE_DISTANCE * REAL_ONE * sang);
M->actor_xyz.z += PXfloat2PXreal(NUDGE_DISTANCE * REAL_ONE * cang);
return (__NUDGED); // we've avoided the hit
}
}
}
}
} // nudge for loop
} // if player
adjusted_pan = FLOAT_ZERO;
made_adjust = FALSE8;
normalAngle = 3 * FULL_TURN; // place holder to mean not set
int32 nFortKnox = 0;
uint32 nBarriers = (M->number_of_barriers + M->number_of_animating);
for (j = 0; j < nBarriers; j++) {
int32 b = Fetch_megas_barrier_number(j);
bar = session_barriers->Fetch_barrier(b);
ignoreBarrier[j] = 1;
if ((PXfloat)PXfabs(newy - bar->bottom()) > BARRIER_TOO_HIGH)
continue; // ignore abars that are now too high
__barrier_result result = Check_this_barrier(bar, newx, newz, oldx, oldz, bar_close, &ignoreThis);
// Ignore barrier culling isn't working - so do them all except animating barriers
ignoreThis = 0;
ignoreBarrier[j] = ignoreThis;
if (ignoreThis == 0)
nFortKnox++;
if (result != __OK)
return (result);
}
if ((!made_adjust) && (MS->player.player_status != RUNNING) && (MS->player.player_status != WALKING)) {
// didnt hit a normal barrier so check if we hit a stair or ladder barrier
// check for stair entry complience - oh yes
for (j = 0; j < num_stairs; j++) {
bar = &stairs[j].bar;
if (newy != bar->bottom())
continue; // not on our floor so continue with next
__barrier_result result = Check_this_barrier(bar, newx, newz, oldx, oldz, bar_close, &ignoreThis);
if (result != __OK)
return (result);
}
}
// if we hit a single corectable barrier then we can make that adjustment now
int32 repulsed = 0;
PXfloat destx = FLOAT_ZERO;
PXfloat destz = FLOAT_ZERO;
if (made_adjust) {
L->pan = adjusted_pan;
if (normalAngle < 2 * FULL_TURN) {
// Repulse the mega back a bit
PXfloat ang = normalAngle * TWO_PI;
PXfloat cang = (PXfloat)PXcos(ang);
PXfloat sang = (PXfloat)PXsin(ang);
// Let's ignore the zero*something as it is always zero
// the stored angle normalAngle is a normal angle pointing away
// from the barrier by 90 deg AND towards the players side of the
// barrier
repulsed = 1;
destx = M->actor_xyz.x + PXfloat2PXreal(REPULSE_DISTANCE * REAL_ONE * sang);
destz = M->actor_xyz.z + PXfloat2PXreal(REPULSE_DISTANCE * REAL_ONE * cang);
}
} else {
destx = newx;
destz = newz;
}
// Right so finally do a line intersection between the old position and the "final" new position
// old position is : oldx, oldz
// new position is : destx, destz
int32 hit = 0;
// Special treatment for the player
if (pl) {
for (j = 0; j < nBarriers; j++) {
int32 b = Fetch_megas_barrier_number(j);
bar = session_barriers->Fetch_barrier(b);
// Ignore barriers which are in the ignore list
if (ignoreBarrier[j] == 1)
continue;
hit = troute.Get_intersect(oldx, oldz, destx, destz, bar->x1(), bar->z1(), bar->x2(), bar->z2());
if (hit == 1) {
warning("Player crossed the line nBars %d nFortKnox %d : player %f %f -> %f %f bar: %f %f -> %f %f", nBarriers, nFortKnox, oldx, oldz, destx, destz,
bar->x1(), bar->z1(), bar->x2(), bar->z2());
break;
}
}
// Oh dear we went through a barrier
if (hit == 1)
return (__BLOCKED); // conflict, so finish
}
// The repulsed position looks good - so use it !
if (repulsed) {
M->actor_xyz.x = destx;
M->actor_xyz.z = destz;
}
// Return the correct values
if (made_adjust)
return (__CORRECTED);
// finally, if player is still looking good then do a check for him hitting other megas
if (pl) {
/*
/
mega /
position : mx, mz /
* /
/
/
/
/
/
/
/
/
/ - his pan direction
#
player @ position : px, pz direction: pan
dx = PXsin( pan )
dz = PXcos( pan )
then the mega is on the left-hand side of the line (or on the line)
if ( (dz * ( mx - px )) <= ( dx * ( mz - pz )) )
else
// he is on the right-hand side of the line
*/
static int32 total_adjusts = 0;
if ((!total_adjusts) && (MS->player.interact_selected) && (logic_structs[MS->player.cur_interact_id]->image_type == VOXEL)) {
// player is highlighting a mega
// check nearness
PXreal sub1, sub2;
sub1 = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.x - M->actor_xyz.x;
sub2 = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.z - M->actor_xyz.z;
// dist
PXreal distance = ((sub1 * sub1) + (sub2 * sub2));
// near
if (distance < (120 * 120)) {
if ((MS->player.cur_state.momentum != __FORWARD_1) && (MS->player.cur_state.momentum != __FORWARD_2))
return __OK;
PXreal dx = (PXreal)PXsin(L->pan * TWO_PI);
PXreal dz = (PXreal)PXcos(L->pan * TWO_PI);
PXreal mx = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.x;
PXreal mz = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.z;
if ((dz * (mx - M->actor_xyz.x)) <= (dx * (mz - M->actor_xyz.z))) {
// right
if ((distance > (50 * 50)) && (distance < (120 * 120)))
L->pan += 0.03f;
} else {
// left
if ((distance > (50 * 50)) && (distance < (120 * 120)))
L->pan -= 0.03f;
}
total_adjusts++;
return (__OK);
}
}
total_adjusts = 0; // reset
}
return (__OK);
}
__barrier_result _game_session::Check_this_barrier(_route_barrier *bar, PXreal newx, PXreal newz, PXreal /* oldx */, PXreal /* oldz */, PXreal bar_close, int32 *ignoreThis) {
PXfloat delta;
PXfloat delta2;
PXfloat barrier_tolerance = BARRIER_TOLERANCE; // 1/8 of a turn = 45 degress
PXreal pdist, dist;
PXreal ignore_bar_close = IGNORE_BARRIER_CLOSE;
*ignoreThis = 1;
pdist = ((newx * bar->bcm().lpx()) + (newz * bar->bcm().lpz())) - bar->bcm().linedist();
if ((PXfloat)PXfabs(pdist) < bar_close) {
// we are near the plane so now we must check the end points
// check the left end of the line
dist = ((newx * bar->bcm().alpx()) + (newz * bar->bcm().alpz())) - bar->bcm().alinedist();
// check the right end
if (dist >= 0) {
dist = ((newx * bar->bcm().blpx()) + (newz * bar->bcm().blpz())) - bar->bcm().blinedist();
if (dist >= 0) {
*ignoreThis = 0;
// we are going to hit this barrier
// but, if the angle is narrow we can aquire the barriers pan and continue unmolested
delta = remainder(L->pan - bar->pan(), FULL_TURN, HALF_TURN);
delta2 = delta;
if (delta < -QUARTER_TURN)
delta2 += HALF_TURN;
if (delta > QUARTER_TURN)
delta2 -= HALF_TURN;
if (PXfabs(delta2) < barrier_tolerance) {
if (made_adjust)
return (__BLOCKED); // conflict, so finish
if ((delta > QUARTER_TURN) || (delta < -QUARTER_TURN)) {
adjusted_pan = remainder(bar->pan() + HALF_TURN, FULL_TURN, HALF_TURN);
} else {
adjusted_pan = bar->pan();
}
made_adjust = TRUE8;
if (adjusted_pan > L->pan) {
adjusted_pan += REPEL_TURN;
} else if (adjusted_pan < L->pan) {
adjusted_pan -= REPEL_TURN;
}
if (pdist > 0)
normalAngle = bar->pan() + QUARTER_TURN;
else if (pdist < 0)
normalAngle = bar->pan() - QUARTER_TURN;
} else {
// cant adjust
return (__BLOCKED);
}
} else
*ignoreThis = 1;
} else
*ignoreThis = 1;
} else if ((PXfloat)PXfabs(pdist) < ignore_bar_close) {
*ignoreThis = 0;
}
return __OK;
}
void _barrier_handler::___init() {
_routing_slice *slice;
uint32 *num_bars;
uint32 len;
Zdebug("_barrier_handler");
Zdebug("\n+init _barrier_handler %s", MS->Fetch_session_name());
// load the raw barrier file for this session
// When clustered the session files have the base stripped
len = sprintf(temp_buf, "%s", PX_FILENAME_BARRIERLIST);
if (len > ENGINE_STRING_LEN)
Fatal_error("_barrier_handler::___init string len error");
Tdebug("barriers.txt", "%s", (const char *)temp_buf);
uint32 buf_hash = NULL_HASH;
uint32 cluster_hash = MS->Fetch_session_cluster_hash();
raw_barriers = (_linked_data_file *)private_session_resman->Res_open(temp_buf, buf_hash, MS->Fetch_session_cluster(), cluster_hash);
num_bars = (uint32 *)raw_barriers->Fetch_item_by_name("Count");
total_barriers = *(num_bars);
Tdebug("barriers.txt", "%d raw barriers", total_barriers);
// load in the routing wrapper
// When clustered the session files have the base stripped
len = sprintf(temp_buf, "%s", PX_FILENAME_ROUTING);
if (len > ENGINE_STRING_LEN)
Fatal_error("_barrier_handler::___init string len error");
Tdebug("barriers.txt", "%s", temp_buf);
buf_hash = NULL_HASH;
route_wrapper = (_linked_data_file *)private_session_resman->Res_open(temp_buf, buf_hash, MS->Fetch_session_cluster(), cluster_hash);
total_slices = route_wrapper->Fetch_number_of_items();
if (total_slices > MAX_slices)
Fatal_error("_barrier_handler::___init finds too many slices - %d but only %d allowed", total_slices, MAX_slices);
Tdebug("slice.txt", "%d routing levels", total_slices);
if (!total_slices) {
Zdebug("[%s]", (const char *)temp_buf);
Fatal_error("no parent routing levels (no parent boxes) engine cannot proceed");
}
uint32 j;
for (j = 0; j < total_slices; j++) {
slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(j);
Tdebug("slice.txt", "bottom %3.1f top %3.1f", slice->bottom, slice->top);
Tdebug("slice.txt", "%d parents", slice->num_parent_boxes);
}
// reset prop list for each
// fully reset abar systems
for (j = 0; j < MAX_slices; j++) {
anim_slices[j].num_props_in_slice = 0;
for (uint32 l = 0; l < MAX_parents_per_anim_slice; l++)
anim_slices[j].anim_parents[l] = nullptr; // unasigned pointer
}
for (j = 0; j < MAX_props; j++) {
anim_prop_info[j].barriers_per_state = 0;
anim_prop_info[j].total_states = 0;
}
for (j = 0; j < MAX_floors; j++) // reset the unassigned parents
anim_parent_table[j].num_props = 0;
parents_used = 0; // no parents have been assigned
Zdebug("anim bars");
Prepare_animating_barriers();
Zdebug("done barriers");
}
#define ADD_CHILD \
if (clist[j]->num_barriers) \
for (k = 0; k < clist[j]->num_barriers; k++) { \
bar = Fetch_barrier(clist[j]->barriers[k]); \
if (bar->bottom() == y) { \
if (barrier_mask) { \
if (MS->troute.LineIntersectsRect(mask, (int32)bar->x1(), (int32)bar->z1(), (int32)bar->x2(), (int32)bar->z2())) \
MS->troute.Add_barrier(bar); \
} else \
MS->troute.Add_barrier(bar); \
} \
}
#define EXPAND_ROUTE_BOX \
if (CHILDL < RBL) \
RBL = CHILDL; \
if (CHILDR > RBR) \
RBR = CHILDR; \
if (CHILDT < RBT) \
RBT = CHILDT; \
if (CHILDB > RBB) \
RBB = CHILDB; \
expanded_this_go++;
#define CHILDL clist[j]->left
#define CHILDR clist[j]->right
#define CHILDT clist[j]->back
#define CHILDB clist[j]->front
#define RBL rb.x1
#define RBR rb.x2
#define RBT rb.z1
#define RBB rb.z2
void _barrier_handler::Form_parent_barrier_list(PXreal x, PXreal y, PXreal z) {
// we are routing into a room - just get the parent barriers
_parent_box *endb;
uint32 parent_a, slice_a, k;
_route_barrier *bar;
uint32 *array;
endb = Fetch_parent_box_for_xyz(x, y, z, parent_a, slice_a);
if (!endb)
return; // will be because of between floor gap - not to worry
if (endb->num_barriers) {
array = (uint32 *)(((char *)endb) + (endb->barriers));
for (k = 0; k < endb->num_barriers; k++) {
bar = Fetch_barrier(array[k]);
MS->troute.Add_barrier(bar);
}
}
}
void _barrier_handler::Form_route_barrier_list(PXreal x, PXreal y, PXreal z, PXreal x2, PXreal z2) {
// add all barriers to the prim route building system for the route x,z,x2,z2
// after this the route_manager can call the prim route builder for the final route to be made
// the restriction is that we can only route from one place to another within a single floor-rect/parent-box
// or
// from within one parent-box/floor-rect to an adjacent parent-box/floor-rect
// it is a higher level job to divide long routes up into rect to rect chunks before calling here
// but this is quite sensible anyway as we only want to be auto-routing across tiny areas at a time
_parent_box *startb;
_parent_box *endb;
_rect rb; // rb meaning 'Route-Box'
uint32 j;
_child_group *clist[MAX_child_groups_per_parent * 2];
uint32 total_childs = 0; // separate total for safety
int32 expanded_this_go;
_route_barrier *bar;
uint32 k;
uint32 parent_a, parent_b;
uint32 slice_a, slice_b;
// which floors are the start and end positions in?
// list child boxes for each floor - ignoring the parent box concept?
// build route
// add parent boundaries for all parents that the final route box intersects - !?!
// find the parent box
// first, find _parent_box for start point and end points
startb = Fetch_parent_box_for_xyz(x, y, z, parent_a, slice_a);
endb = Fetch_parent_box_for_xyz(x2, y, z2, parent_b, slice_b);
if ((!startb) && (endb))
startb = endb; // no start but end
if ((!endb) && (startb))
endb = startb; // no end but start
if (!startb)
Fatal_error("_barrier_handler::Form_route_barrier_list start and end not on floor - %s", MS->Fetch_object_name(MS->Fetch_cur_id()));
// make a list of pointers to the child groups
if (startb != endb) { // oh dear - not going to allow this anymore
Form_parent_barrier_list(x2, y, z2);
Form_parent_barrier_list(x, y, z);
return;
}
Zdebug("%3.1f %3.1f %3.1f %3.1f", startb->back, startb->left, startb->front, startb->right);
if (startb->num_childgroups) {
for (j = 0; j < startb->num_childgroups; j++) {
if (total_childs == (MAX_child_groups_per_parent * 2))
Fatal_error("_barrier_handler::Form_route_barrier_list - clist ran out of space");
clist[total_childs++] = Fetch_child_box(startb, j);
}
}
// we now know the _parent_box that our start point is on - we therefore have the list of child boxes
// same or different?
if (startb != endb) { // different
Zdebug("different parent for end box");
if (endb->num_childgroups) {
Zdebug("adding %d child boxes for end point", endb->num_childgroups);
for (j = 0; j < endb->num_childgroups; j++) {
if (total_childs == (MAX_child_groups_per_parent * 2))
Fatal_error("_barrier_handler::Form_route_barrier_list - clist ran out of space");
clist[total_childs++] = Fetch_child_box(endb, j);
}
}
}
// ok, we now have a list of pointers to all the child groups relevant
// create the initial route box
if (x < x2) {
rb.x1 = x;
rb.x2 = x2;
} else {
rb.x1 = x2;
rb.x2 = x;
}
if (z < z2) {
rb.z1 = z;
rb.z2 = z2;
} else {
rb.z1 = z2;
rb.z2 = z;
}
// we now have our initial route box
// enter our main loop
do {
expanded_this_go = 0; // flag to say whether or no the route-box got expanded this loop
for (j = 0; j < total_childs; j++) {
if (clist[j]) {
// child not deleted
if (((CHILDR < RBL) || (CHILDL > RBR)) && ((CHILDB < RBT) || (CHILDT > RBB))) {
// child is wholly outside the route box - do nothing except prime the ELSE
} else if (((CHILDR >= RBL) && (CHILDL <= RBR)) && ((CHILDB >= RBT) && (CHILDT <= RBB))) {
// child is wholly inside route box - add it and delete child
ADD_CHILD
clist[j] = nullptr; // delete the child now it has been absorbed
} else if (((RBR >= CHILDL) && (RBL <= CHILDR)) && ((RBT >= CHILDT) && (RBB <= CHILDB))) {
// route box is wholly inside child box - expand route box, add and delete child
ADD_CHILD
clist[j] = nullptr; // delete the child now it has been absorbed
EXPAND_ROUTE_BOX
} else {
if ((CHILDL > RBL) && (CHILDL < RBR) && ((CHILDT > RBT) && (CHILDT < RBB))) {
// child top/left is within route box - expand route box, add and delete child
ADD_CHILD
clist[j] = nullptr; // delete the child now it has been absorbed
EXPAND_ROUTE_BOX
} else if ((CHILDR > RBL) && (CHILDR < RBR) && ((CHILDT > RBT) && (CHILDT < RBB))) {
// child top/right is within route box - expand route box, add and delete child
ADD_CHILD
clist[j] = nullptr; // delete the child now it has been absorbed
EXPAND_ROUTE_BOX
} else if ((CHILDL > RBL) && (CHILDL < RBR) && ((CHILDB > RBT) && (CHILDB < RBB))) {
// child bottom/left is within route box - expand route box, add and delete child
ADD_CHILD
clist[j] = nullptr; // delete the child now it has been absorbed
EXPAND_ROUTE_BOX
} else if ((CHILDR > RBL) && (CHILDR < RBR) && ((CHILDB > RBT) && (CHILDB < RBB))) {
// child bottom/right is within route box - expand route box, add and delete child
ADD_CHILD
clist[j] = nullptr; // delete the child now it has been absorbed
EXPAND_ROUTE_BOX
} else {
// we must check for our route line intersecting a horizontal and vertical child box edge
}
}
}
}
// if this loop we did not expand the route_box then we quit this DO-WHILE loop
if (!expanded_this_go)
break;
} while (1);
// if there are two parent boxes we must add the parent barriers from each to the list
if (startb != endb) {
// add both parent box barriers in
uint32 *array;
if (startb->num_barriers) {
array = (uint32 *)(((char *)startb) + (startb->barriers));
for (k = 0; k < startb->num_barriers; k++) {
bar = Fetch_barrier(array[k]);
MS->troute.Add_barrier(bar);
}
}
if (endb->num_barriers) {
array = (uint32 *)(((char *)endb) + (endb->barriers));
for (k = 0; k < endb->num_barriers; k++) {
bar = Fetch_barrier(array[k]);
MS->troute.Add_barrier(bar);
}
}
} else { // route lies within a single floor - so draw a box around it
_route_barrier newbar;
// left hand barrier
newbar.x1(startb->left);
newbar.z1(startb->back);
newbar.x2(startb->left);
newbar.z2(startb->front);
MS->troute.Add_barrier(&newbar);
// right hand barrier
newbar.x1(startb->right);
newbar.z1(startb->back);
newbar.x2(startb->right);
newbar.z2(startb->front);
MS->troute.Add_barrier(&newbar);
// top barrier
newbar.x1(startb->left);
newbar.z1(startb->back);
newbar.x2(startb->right);
newbar.z2(startb->back);
MS->troute.Add_barrier(&newbar);
// bottom barrier
newbar.x1(startb->left);
newbar.z1(startb->front);
newbar.x2(startb->right);
newbar.z2(startb->front);
MS->troute.Add_barrier(&newbar);
}
}
_parent_box *_barrier_handler::Fetch_parent_num_on_slice_y(uint32 requested_parent, PXreal y) {
// fetch the parent of the number passed for a given y level
// ie 0 means first, 1 means second, etc
// this is called by the plan-viewer which just keeps asking for the next one until we say there are no more
// by passing back a 0 instead of a pointer to a parent
static _routing_slice *slice;
uint32 cur_slice = 0;
// first time in so compute the slice
if (!requested_parent) {
while (1) {
slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(cur_slice);
if ((y >= slice->bottom) && (y < slice->top))
break;
// safety
cur_slice++;
if (cur_slice == total_slices) // if so then must be last slice :O
Fatal_error("Fetch_parent_num_on_slice_y ran out of slices");
// next
slice++;
}
}
// ok, we have the slice
// return the parent of the requested number - or, 0 if there is no more
// reached total?
if (requested_parent == slice->num_parent_boxes)
return (nullptr);
// simply return the pointer
return ((_parent_box *)(((uint8 *)slice) + slice->parent_boxes[requested_parent]));
}
_route_barrier *_barrier_handler::Fetch_barrier(uint32 num) {
// return a pointer to numbered barrier
_route_barrier *bar;
assert(num < total_barriers);
if (num >= total_barriers)
Fatal_error("illegal barrier request %d", num);
bar = (_route_barrier *)raw_barriers->Fetch_item_by_name("Data");
return &bar[num];
}
_parent_box *_barrier_handler::Fetch_parent_box_for_xyz(PXreal x, PXreal y, PXreal z, uint32 &par_num, uint32 &slice_num) {
// return a pointer to the parent box of a point in world space
// returns 0 if the point does not lie within a parent box
_routing_slice *slice = nullptr;
_parent_box *parent = nullptr;
// find correct slice according to height
// fetch first
slice_num = 0;
while (1) {
slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(slice_num);
if ((y >= slice->bottom) && (y < slice->top))
break;
// safety
slice_num++;
if (slice_num == total_slices) { // if so then must be last slice :O
Fatal_error("_barrier_handler::Fetch_parent_box_for_xyz ran out of slices: object [%s] (%3.1f %3.1f %3.1f) has an "
"illegal marker",
MS->Fetch_object_name(MS->Fetch_cur_id()), x, y, z);
}
// next
slice++;
}
// ok, we found the right y slice
// now find the right parent box
if (!slice->num_parent_boxes)
Fatal_error("_barrier_handler::Fetch_parent_box_for_xyz slice has no parent boxes");
for (par_num = 0; par_num < slice->num_parent_boxes; par_num++) {
parent = (_parent_box *)(((uint8 *)slice) + slice->parent_boxes[par_num]);
// do we lie within the box?
if ((x > parent->left) && (x < parent->right) && (z > parent->back) && (z < parent->front)) {
return (parent);
}
}
return (nullptr);
}
void _game_session::Prepare_megas_route_barriers(bool8 pl) {
// see which parent box we're owned by
// if different from previous fetch all the barriers for the new parent
// this system is custom for the player object - routing megas use their own system
// this routine fecthes the 'special' player only line-of-sight barriers too
_parent_box *par = nullptr;
_child_group *pchild;
uint32 total_childs;
uint32 j, k;
uint32 *list;
_route_barrier *bar;
uint32 parent_number;
_routing_slice *slice;
PXreal x, y, z;
x = M->actor_xyz.x;
y = floor_def->Return_true_y(M->actor_xyz.y);
z = M->actor_xyz.z;
// on previous slice?
slice = (_routing_slice *)session_barriers->route_wrapper->Fetch_item_by_number(M->cur_slice);
if ((y >= slice->bottom) && (y < slice->top) && (M->cur_parent))
if ((x > M->cur_parent->left) && (x < M->cur_parent->right) && (z > M->cur_parent->back) && (z < M->cur_parent->front)) {
// nothing has changed
Prepare_megas_abarriers(M->cur_slice, M->par_number);
// player should have added the barriers of stood megas
if (pl)
Fetch_mega_barriers_for_player();
return;
}
M->cur_slice = 0;
while (1) {
slice = (_routing_slice *)session_barriers->route_wrapper->Fetch_item_by_number(M->cur_slice);
if ((y >= slice->bottom) && (y < slice->top))
break;
// safety
M->cur_slice++;
if (M->cur_slice == session_barriers->total_slices) { // if so then must be last slice :O
M->cur_slice--;
slice = (_routing_slice *)session_barriers->route_wrapper->Fetch_item_by_number(M->cur_slice);
break;
}
}
// ok, we found the right y slice
// now find the right parent box
if (!slice->num_parent_boxes)
Fatal_error("Prepare_megas_route_barriers slice has no parent boxes");
for (parent_number = 0; parent_number < slice->num_parent_boxes; parent_number++) {
par = (_parent_box *)(((uint8 *)slice) + slice->parent_boxes[parent_number]);
// do we lie within the box?
if ((x > par->left) && (x < par->right) && (z > par->back) && (z < par->front)) {
break; // found
}
}
if (parent_number == slice->num_parent_boxes) {
// not on a legal position - can happen
M->cur_parent = nullptr; // null pointer
M->number_of_barriers = 0;
M->number_of_nudge = 0;
M->number_of_animating = 0;
return;
}
// has a parent box different from the current one been found?
{
// new one
M->cur_parent = par;
M->par_number = parent_number;
// reset list of barrier ids
M->number_of_barriers = 0;
M->number_of_animating = 0;
// firstly, drag out the parents bounding barriers if it has any
if (par->num_barriers) {
list = (uint32 *)((uint8 *)par + par->barriers);
// get all the barriers
for (j = 0; j < par->num_barriers; j++) {
// fetch each barrier and check that its bottom edge is on the floor - otherwise we ignore it
bar = session_barriers->Fetch_barrier(*(list));
if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
// ok, this barrier is on the floor so we add it to our list
M->barrier_list[M->number_of_barriers++] = *(list++);
}
}
}
if (pl)
M->number_of_nudge = 0; // reset now - in case there are none
// now player only specials
if ((pl) && (par->num_specials)) {
#ifdef VERBOSE
Zdebug("getting player specials");
#endif
list = (uint32 *)((uint8 *)par + par->specials);
// get all the barriers
for (j = 0; j < par->num_specials; j++) {
// fetch each barrier and check that its bottom edge is on the floor - otherwise we ignore it
bar = session_barriers->Fetch_barrier(*(list));
if (bar->material() == VIEW_FIELD) {
if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
// ok, this barrier is on the floor so we add it to our list
M->barrier_list[M->number_of_barriers++] = *(list++);
}
} else if (bar->material() >= LEFT_NUDGE) {
if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
// ok, this barrier is on the floor so we add it to our list
M->nudge_list[M->number_of_nudge++] = *(list++);
}
} else {
Fatal_error("illegal barrier [%d], special list - type %d, x1 %3.2f, x2 %3.2f, z1 %3.2f, z2 %3.2f", *(list), bar->material(), bar->x1(),
bar->x2(), bar->z1(), bar->z2());
}
}
}
// find out have many child boxes this parent has
total_childs = session_barriers->Fetch_number_of_child_boxes(par);
for (j = 0; j < total_childs; j++) {
pchild = session_barriers->Fetch_child_box(par, j);
for (k = 0; k < pchild->num_barriers; k++) {
bar = session_barriers->Fetch_barrier(pchild->barriers[k]);
if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
M->barrier_list[M->number_of_barriers++] = pchild->barriers[k];
}
}
}
}
// now build the animating barrier list - regardless of whether or not the parent has changed
Prepare_megas_abarriers(M->cur_slice, M->par_number);
if (M->number_of_barriers + M->number_of_animating > MAX_bars)
Fatal_error("[%s] finds too many barriers - found %d + %d animating, total max %d", object->GetName(), M->number_of_barriers, M->number_of_animating, MAX_bars);
if (M->number_of_nudge > MAX_bars)
Fatal_error("too many player nudge barriers");
}
void _barrier_handler::Prepare_animating_barriers() {
// the nightmare that is animating barriers
// search through all prop animations getting out the animating barriers - checking for duplicates
#define MAX_anim_barriers 400
uint32 j;
uint16 barrier_table[MAX_anim_barriers];
uint32 total_anim_bars = 0;
_route_barrier *bar;
_routing_slice *slice;
_parent_box *parent;
uint32 cur_slice = 0;
uint32 l, f, pbar_num;
uint32 abar_index = 0;
Tdebug("anim_barriers.txt", "Preparing animating barriers");
for (j = 0; j < MS->prop_anims->Fetch_number_of_items(); j++) {
Tdebug("anim_barriers.txt", "\n%d %s", j, MS->prop_anims->Fetch_items_name_by_number(j));
_animating_prop *index;
_animation_entry *anim;
index = (_animating_prop *)MS->prop_anims->Fetch_item_by_number(j);
Tdebug("anim_barriers.txt", " has %d anims", index->num_anims);
// loop through all looking for our named anim
if (index->num_anims) {
// get the prop number
for (uint32 k = 0; k < index->num_anims; k++) {
anim = (_animation_entry *)(((char *)index) + index->anims[k]);
Tdebug("anim_barriers.txt", " '%s' - %d frames", (((char *)index) + anim->name), anim->num_frames);
if (anim->num_barriers_per_frame) {
Tdebug("anim_barriers.txt", " has %d anim barriers per frame", anim->num_barriers_per_frame);
uint16 *bars = (uint16 *)(((char *)index) + anim->offset_barriers);
for (uint32 i = 0; i < (uint32)(anim->num_barriers_per_frame * anim->num_frames); i++) {
if (bars[i] != 0xffff) {
// check each barrier for duplication and add in to correct slice, parent list
for (l = 0; l < total_anim_bars; l++) {
if (barrier_table[l] == bars[i]) {
Tdebug("anim_barriers.txt", " %d in list already - index %d", bars[i], i);
break; // found this bar
}
}
// i is barrier index
bar = Fetch_barrier(bars[i]);
if (l == total_anim_bars) { // didnt find in list
Tdebug("anim_barriers.txt", " new barrier %d x%3.2f y%3.2f z%3.2f", bars[i], bar->x1(), bar->bottom(),
bar->z1());
barrier_table[total_anim_bars++] = (uint16)bars[i]; // write the bar down
if (total_anim_bars == MAX_anim_barriers)
Fatal_error("Prepare_animating_barriers finds too many barriers "
"for scratch table");
}
cur_slice = 0;
do {
slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(cur_slice);
if ((bar->bottom() >= slice->bottom) && (bar->bottom() < slice->top))
break;
cur_slice++;
} while (cur_slice != total_slices);
if (cur_slice == total_slices) { // if so then must be last slice :O
Tdebug("anim_barriers.txt", " **ran out of slices :O\n");
} else {
Tdebug("anim_barriers.txt", " exists on slice %d", cur_slice);
// check legality of number of parents
if (slice->num_parent_boxes > MAX_parents_per_anim_slice)
Fatal_error("prepare anim barriers finds too many parents in slice "
"- %d parents",
slice->num_parent_boxes);
int32 prop_number =
MS->objects->Fetch_item_number_by_name((const char *)MS->prop_anims->Fetch_items_name_by_number(j));
if (prop_number == -1) {
Tdebug("anim_barriers.txt", " !!associated prop [%s] not a game object - so ignoring",
(const char *)MS->prop_anims->Fetch_items_name_by_number(j));
} else {
// now find parent the barrier would belong to
for (f = 0; f < slice->num_parent_boxes; f++) {
Tdebug("anim_barriers.txt", " check parent %d", f);
parent = (_parent_box *)(((uint8 *)slice) + slice->parent_boxes[f]);
// do we lie within the box?
if ((bar->x1() > parent->left) && (bar->x1() < parent->right) && (bar->z1() > parent->back) &&
(bar->z1() < parent->front)) {
char *props_name = (char *)MS->prop_anims->Fetch_items_name_by_number(j);
uint32 props_number = MS->objects->Fetch_item_number_by_name(props_name);
if (!anim_slices[cur_slice].anim_parents[f]) {
anim_slices[cur_slice].anim_parents[f] = &anim_parent_table[parents_used++];
Tdebug("anim_barriers.txt", " new aparent");
}
pbar_num = anim_slices[cur_slice].anim_parents[f]->num_props;
uint32 n;
for (n = 0; n < pbar_num; n++)
if (anim_slices[cur_slice].anim_parents[f]->prop_number[n] == props_number)
break;
if (n == pbar_num) { // new
anim_slices[cur_slice].anim_parents[f]->num_props++;
if (pbar_num == MAX_props_per_parent)
Fatal_error("too many props in "
"parent - max = %d",
MAX_props_per_parent);
Tdebug("anim_barriers.txt", " found - slice %d, parent %d "
"[%d bars so far], prop [%s, %d] state "
"%d\n",
cur_slice, f, anim_slices[cur_slice].anim_parents[f]->num_props, props_name,
props_number, anim->frames[i / anim->num_barriers_per_frame]);
anim_slices[cur_slice].anim_parents[f]->prop_number[pbar_num] = (uint8)props_number;
}
break;
}
}
if (f == slice->num_parent_boxes)
Tdebug("anim_barriers.txt", " !!barrier not located within a parent box!!\n");
}
}
} else
Tdebug("anim_barriers.txt", " !!barrier is type 0xffffffff");
}
} else
Tdebug("anim_barriers.txt", " 0 anim bars");
}
}
}
// now reverse engineer the target lists
for (j = 0; j < total_slices; j++) {
Tdebug("anim_barriers.txt", " slice %d", j);
for (uint32 k = 0; k < MAX_parents_per_anim_slice; k++) {
if (!anim_slices[j].anim_parents[k])
Tdebug("anim_barriers.txt", " par %d free", k);
else {
Tdebug("anim_barriers.txt", " parent %d has %d animating props", k, anim_slices[j].anim_parents[k]->num_props);
for (uint32 i = 0; i < anim_slices[j].anim_parents[k]->num_props; i++)
Tdebug("anim_barriers.txt", " prop num %d", anim_slices[j].anim_parents[k]->prop_number[i]);
}
}
}
Tdebug("anim_barriers.txt", "\n\n\n\n\n--------preparing prop slice format---------------\n");
uint32 total_states, i;
// now compute the special prop table for run-time LOS injection
// first reset special prop fixed list
for (j = 0; j < MAX_props; j++)
anim_prop_info[j].barriers_per_state = 0; // do it here so it can double up as 0 being an unused entry
for (j = 0; j < MS->prop_anims->Fetch_number_of_items(); j++) {
Tdebug("anim_barriers.txt", "\n**%d %s", j, MS->prop_anims->Fetch_items_name_by_number(j));
_animating_prop *index;
_animation_entry *anim;
index = (_animating_prop *)MS->prop_anims->Fetch_item_by_number(j);
// loop through all looking for our named anim
if (index->num_anims) {
// got a prop
// it has anims
// is it a prop with animating barriers?
// get first anim
anim = (_animation_entry *)(((char *)index) + index->anims[0]);
// does it have anim barriers
if (anim->num_barriers_per_frame) {
// ok, we're on
Tdebug("anim_barriers.txt", " has %d anims and %d per frame", index->num_anims, anim->num_barriers_per_frame);
// reset our total number of states for this prop counter
total_states = 0;
// find the first legal barrier in this anim
uint16 *bars = (uint16 *)(((char *)index) + anim->offset_barriers);
i = 0;
while ((bars[i] == 0xffff) && (i < (uint32)(anim->num_barriers_per_frame * anim->num_frames)))
i++;
// better make sure the anim has a legal barrier - if not then assume the prop is well knackered and leave
// it out of the anim barrier system
if (i < (uint32)(anim->num_barriers_per_frame * anim->num_frames)) {
// get our chosen sample barrier
bar = Fetch_barrier(bars[i]);
// now compute slice for sample barrier
cur_slice = 0;
do {
slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(cur_slice);
if ((bar->bottom() >= slice->bottom) && (bar->bottom() < slice->top))
break;
cur_slice++;
} while (cur_slice != total_slices);
// check for not on a slice - not good
if (cur_slice == total_slices) { // if so then must be last slice :O
Tdebug("anim_barriers.txt", " **ran out of slices :O\n");
} else {
Tdebug("anim_barriers.txt", " sample bar puts prop in slice %d", cur_slice);
// get the prop number
uint32 prop_number = MS->objects->Fetch_item_number_by_name((const char *)MS->prop_anims->Fetch_items_name_by_number(j));
// gotta check for anims with no equivelent game objects
if (prop_number != 0xffffffff) {
Tdebug("anim_barriers.txt", " listing as prop number %d", anim_slices[cur_slice].num_props_in_slice);
// ok, add the prop to the slices list of props
anim_slices[cur_slice].prop_list[anim_slices[cur_slice].num_props_in_slice++] = (uint8)prop_number;
if (anim_slices[cur_slice].num_props_in_slice >= MAX_props)
Fatal_error("form anim barrier list found too many props in the slice");
// set number of barriers per frame for this prop
anim_prop_info[prop_number].barriers_per_state = anim->num_barriers_per_frame; // set from our sample first anim
// now loop through all the anims filling in the state table
// in theory, having done this, there will be entries for each state referenced
for (uint32 k = 0; k < index->num_anims; k++) {
// get anim k
anim = (_animation_entry *)(((char *)index) + index->anims[k]);
// get anims list of barriers
uint16 *barriers = (uint16 *)(((char *)index) + anim->offset_barriers);
// go through each frame/state
for (uint32 c = 0; c < anim->num_frames; c++) {
// get state
uint32 state = anim->frames[c];
// keep computing the total number of states for this prop
if (state > total_states)
total_states = state;
// for each state go through all the barriers per frame/state
for (i = 0; i < anim->num_barriers_per_frame; i++) {
// gotta check for funny illegal barriers
if (barriers[(c * anim->num_barriers_per_frame) + i] != 0xffff) {
// legal barrier
barrier_table[(state * anim->num_barriers_per_frame) + i] =
(uint16)barriers[(c * anim->num_barriers_per_frame) + i];
} else {
// dodgy barrier
// setting to barrier 0 but this is not a proper
// solution
barrier_table[(state * anim->num_barriers_per_frame) + i] = 0;
}
}
}
}
// ok, we've set up the anim barriers for this prop
Tdebug("anim_barriers.txt", " prop [%s] highest state %d, %d bars per state",
(const char *)MS->prop_anims->Fetch_items_name_by_number(j), total_states,
anim_prop_info[prop_number].barriers_per_state);
// note down total states
anim_prop_info[prop_number].total_states = (uint8)(total_states + 1);
// create space for table
Tdebug("anim_barriers.txt", "prop %d needs %d uint16's", prop_number,
(total_states + 1) * anim_prop_info[prop_number].barriers_per_state);
if (abar_index >= MAX_prop_abars)
Fatal_error("too many animating barriers - current max = %d", MAX_prop_abars);
// move the barrier table
memcpy(&prop_abar_table[abar_index], barrier_table,
(sizeof(uint16) * ((total_states + 1) * anim_prop_info[prop_number].barriers_per_state)));
anim_prop_info[prop_number].barrier_list = &prop_abar_table[abar_index];
abar_index += ((total_states + 1) * anim_prop_info[prop_number].barriers_per_state);
} else { // if prop number legal
Tdebug("anim_barriers.txt", " prop has no object - ignoring");
}
}
}
}
}
}
Tdebug("anim_barriers.txt", " ");
for (j = 0; j < MS->Fetch_number_of_objects(); j++)
if (anim_prop_info[j].barriers_per_state) {
Tdebug("anim_barriers.txt", "prop %d", j);
Tdebug("anim_barriers.txt", "prop %d [%s] has %d anim barriers, %d per frame", j, (const char *)MS->objects->Fetch_items_name_by_number(j),
anim_prop_info[j].total_states, anim_prop_info[j].barriers_per_state);
Tdebug("anim_barriers.txt", "total %d", anim_prop_info[j].barriers_per_state * (anim_prop_info[j].total_states));
for (uint16 k = 0; k < anim_prop_info[j].barriers_per_state * (anim_prop_info[j].total_states); k++)
Tdebug("anim_barriers.txt", "%d %d", k, anim_prop_info[j].barrier_list[k]);
}
Tdebug("anim_barriers.txt", "\nDone");
}
uint32 _barrier_handler::Get_anim_barriers(uint32 n, uint32 *oThisCubesBarriers, uint32 slice) {
// gives you all the 'current' anim barriers on an ENTIRE slice
// used by LOS, planview,
uint32 prop_id;
uint32 prop_state;
uint32 bars_per_state;
uint32 bar_index;
uint16 *bars;
uint32 j, k;
// how many props in this slice
uint32 num_props = anim_slices[slice].num_props_in_slice; // prop_list.GetNoItems();
for (j = 0; j < num_props; j++) {
// get id of prop
prop_id = anim_slices[slice].prop_list[j];
// get prop state
prop_state = MS->prop_state_table[prop_id];
// get number of barriers per state
bars_per_state = anim_prop_info[prop_id].barriers_per_state;
// index into barrier list to first barrier for this state
bar_index = (prop_state * bars_per_state);
bars = (uint16 *)&anim_prop_info[prop_id].barrier_list[0];
bars += bar_index;
for (k = 0; k < bars_per_state; k++) {
if (*(bars) >= total_barriers)
Fatal_error("Get_anim_barriers - illegal barrier request %d", *(bars));
oThisCubesBarriers[n++] = (uint32) * (bars++);
}
}
return n;
}
void _game_session::Prepare_megas_abarriers(uint32 slice_number, uint32 parent_number) {
// fetch abars for the current parent ONLY
M->number_of_animating = 0;
uint32 num_props;
uint32 prop_id;
uint32 prop_state;
uint32 bars_per_state;
uint32 bar_index;
uint16 *bars;
uint32 k;
if (!session_barriers->anim_slices[slice_number].anim_parents[parent_number])
return; // parent has none at all
num_props = session_barriers->anim_slices[slice_number].anim_parents[parent_number]->num_props;
for (uint32 i = 0; i < num_props; i++) {
// yup - our parent does have animating props
// get prop id on this parent
prop_id = session_barriers->anim_slices[slice_number].anim_parents[parent_number]->prop_number[i];
// get prop state
prop_state = prop_state_table[prop_id];
// get number of barriers per state
bars_per_state = session_barriers->anim_prop_info[prop_id].barriers_per_state;
// index into barrier list to first barrier for this state
bar_index = (prop_state * bars_per_state);
bars = (uint16 *)&session_barriers->anim_prop_info[prop_id].barrier_list[0];
bars += bar_index;
for (k = 0; k < bars_per_state; k++)
M->barrier_list[M->number_of_barriers + M->number_of_animating++] = (uint32) * (bars++);
}
}
void _game_session::Fetch_mega_barriers_for_player() {
// find all the megas on our floor
// then add in barriers for each of them that is stood
// add the barriers on the end of the anim barrier list which MUST have already been computed
}
} // End of namespace ICB