1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * Additional copyright for this file:
8 * Copyright (C) 1999-2000 Revolution Software Ltd.
9 * This code is based on source code created by Revolution Software,
10 * used with permission.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 *
26 */
27
28 #include "engines/icb/p4.h"
29 #include "engines/icb/common/px_common.h"
30 #include "engines/icb/common/px_floor_map.h"
31 #include "engines/icb/common/px_linkeddatafile.h"
32 #include "engines/icb/common/px_route_barriers.h"
33 #include "engines/icb/common/px_prop_anims.h"
34 #include "engines/icb/mission.h"
35 #include "engines/icb/session.h"
36 #include "engines/icb/debug.h"
37 #include "engines/icb/floors.h"
38 #include "engines/icb/barriers.h"
39 #include "engines/icb/global_objects.h"
40 #include "engines/icb/res_man.h"
41
42 #include "common/textconsole.h"
43
44 namespace ICB {
45
46 // how much you get nudge along a nudge barrier per cycle
47 #define NUDGE_DISTANCE (10)
48
49 // How close you have to get to barriers to consider a collision
50 // Note : the run anim has a delta movement of 30cm hence the 35cm figure
51 #define BARRIER_CLOSE (20 * FLOAT_ONE)
52 #define RUN_BARRIER_CLOSE (35 * FLOAT_ONE)
53
54 // Only do fort-knox solution on barriers closer than this distance
55 #define IGNORE_BARRIER_CLOSE (100 * FLOAT_ONE)
56
57 // made bigger than barrier close so we hit stairs before atual barriers that surround them
58 #define STAIR_CLOSE 25 * FLOAT_ONE
59 #define LADDER_TOP_CLOSE 50 * FLOAT_ONE
60
61 // Ignore barriers that are more than this away from players height
62 #define BARRIER_TOO_HIGH (100 * REAL_ONE)
63
64 // above this angle the mega is blocked, below this angle it is aligned
65 #define BARRIER_TOLERANCE ((FULL_TURN * 70) / 360) // 70 deg
66
67 // For Sony testing make these variables for altering at run-time
68 // in long term they will become constants
69
70 // How much you get reflected away from a barrier when you are aligned with it
71 PXreal REPEL_TURN = ((FULL_TURN * 6) / 360); // 6 deg
72
73 // how much you get repulsed away from a barrier per cycle when you
74 // are being aligned with it
75 PXreal REPULSE_DISTANCE = (15 * REAL_ONE); // 15 cm
76
Check_barrier_bump_and_bounce(PXreal newx,PXreal newy,PXreal newz,PXreal oldx,PXreal,PXreal oldz,bool8 pl)77 __barrier_result _game_session::Check_barrier_bump_and_bounce(PXreal newx, PXreal newy, PXreal newz, PXreal oldx, PXreal /* oldy */, PXreal oldz, bool8 pl) {
78 // see if the coordinates passed are close to the players current barriers
79 // returns 0 no barrier found thats too near
80 // 1 a barrier was too close
81
82 _route_barrier *bar;
83 PXreal pdist, dist;
84 uint32 j;
85 PXfloat barrier_tolerance = BARRIER_TOLERANCE; // 1/8 of a turn = 45 degress
86 PXfloat diff;
87 int32 ignoreThis;
88
89 // 1 = means don't do fort knox solution on this barrier
90 // 0 = means do fort knox solution on this barrier
91 int32 ignoreBarrier[MAX_barriers];
92
93 PXreal bar_close = BARRIER_CLOSE; // changes if player running or walking
94
95 if (pl) {
96 // is player running
97 if (Get_motion() == __MOTION_RUN) // running
98 bar_close = RUN_BARRIER_CLOSE;
99
100 // check for stair entry complience - oh yes
101 for (j = 0; j < num_stairs; j++) {
102
103 bar = &stairs[j].bar;
104
105 // blocked if stair/ladder is disabled
106 if (!stairs[j].live)
107 continue;
108
109 if (newy != bar->bottom())
110 continue; // not on our floor so continue with next
111
112 pdist = ((newx * bar->bcm().lpx()) + (newz * bar->bcm().lpz())) - bar->bcm().linedist();
113
114 if (((PXfloat)PXfabs(pdist) < STAIR_CLOSE) || // stair
115 ((!stairs[j].is_stair) && (!stairs[j].up) && ((PXfloat)PXfabs(pdist) < LADDER_TOP_CLOSE))) { // top of stairs
116 // we are near the plane so now we must check the end points
117 // check the left end of the line
118 dist = ((newx * bar->bcm().alpx()) + (newz * bar->bcm().alpz())) - bar->bcm().alinedist();
119
120 // check the right end
121 if (dist >= 0) {
122 dist = ((newx * bar->bcm().blpx()) + (newz * bar->bcm().blpz())) - bar->bcm().blinedist();
123
124 if (dist >= 0) {
125 // ok, its a hit
126 // we need to crash into the barrier if we're crouched
127
128 if (M->Is_crouched())
129 return __BLOCKED;
130
131 // and crash if we're armed
132 if (M->Fetch_armed_status())
133 return __BLOCKED;
134
135 // must be walking or running upright - so off we go
136
137 diff = L->pan - stairs[j].pan;
138 // correct
139 if (diff > HALF_TURN)
140 diff -= FULL_TURN;
141 else if (diff < -HALF_TURN)
142 diff += FULL_TURN;
143
144 if (PXfabs(diff) < (FULL_TURN / 10)) { // 36 deg = +/- 18 deg
145 L->pan = stairs[j].pan;
146 MS->player.stair_num = (uint8)j; // actual stair index number
147 MS->player.stair_unit = 0; // units into cycle
148 MS->player.stair_dir = stairs[j].up; // 1 is up, 0 is down
149 MS->player.begun_at_bottom = stairs[j].up; // 1 is started at bottom
150 MS->player.was_climbing = FALSE8; // no y movement into the cycle
151
152 if (stairs[j].is_stair) { // stair or ladder
153 M->on_stairs = TRUE8; // for shadow correction system
154
155 // stairs
156 if (Get_motion() == __MOTION_RUN) // running
157 MS->player.Set_player_status(RUNNING_ON_STAIRS);
158
159 else
160 MS->player.Set_player_status(ON_STAIRS);
161
162 if (MS->player.stair_dir) // going up
163 MS->player.step_sample_num = 0; // starting at bottom so sampling starts at 0
164 else
165 MS->player.step_sample_num = TOP_stair_num; // starting at top
166
167 // set the stairway coordinate correction system
168 for (uint32 k = 0; k < MAX_stair_length; k++)
169 MS->player.step_samples[k].stepped_on_step = FALSE8;
170 } else { // ladder
171 MS->player.left_right = 0;
172 if (MS->player.stair_dir) { // going up
173 #define SNAP_BACK_DOWN 70
174 #define SNAP_BACK_UP 25
175 Snap_to_ladder(&stairs[j], SNAP_BACK_UP);
176 MS->player.was_climbing = TRUE8; // into anim has movement
177 MS->player.Easy_start_new_mode(ON_LADDER, __CORD_STAND_TO_CLIMB_UP_LADDER);
178 } else {
179 M->drawShadow = FALSE8; // shadows off
180 Snap_to_ladder(&stairs[j], SNAP_BACK_DOWN);
181 camera_lock = TRUE8; // stop rough room cut through effect
182 MS->player.Easy_start_new_mode(BEGIN_DOWN_LADDER, __STAND_TO_CLIMB_DOWN_LADDER_RIGHT);
183 }
184 return (__NUDGED);
185 }
186 return (__OK);
187 }
188 }
189 }
190 }
191 }
192
193 // check for collision with nudge barriers
194 for (j = 0; j < M->number_of_nudge; j++) {
195 int32 b = Fetch_megas_nudge_barrier_number(j);
196 bar = session_barriers->Fetch_barrier(b);
197
198 pdist = ((newx * bar->bcm().lpx()) + (newz * bar->bcm().lpz())) - bar->bcm().linedist();
199 if ((PXfloat)PXfabs(pdist) < BARRIER_CLOSE) {
200 // we are near the plane so now we must check the end points
201 // check the left end of the line
202 dist = ((newx * bar->bcm().alpx()) + (newz * bar->bcm().alpz())) - bar->bcm().alinedist();
203 // check the right end
204 // Make barrier a bit longer to nudge player through the doorway nicely
205 if (dist > -bar_close) {
206 dist = ((newx * bar->bcm().blpx()) + (newz * bar->bcm().blpz())) - bar->bcm().blinedist();
207 // Make barrier a bit longer to nudge player through the doorway nicely
208 if (dist > -bar_close) {
209 // check angle - narrow ones are ignored
210
211 PXfloat delta = remainder(L->pan - bar->pan(), FULL_TURN, HALF_TURN);
212 PXfloat delta2 = delta;
213
214 if (delta < -QUARTER_TURN)
215 delta2 += HALF_TURN;
216 if (delta > QUARTER_TURN)
217 delta2 -= HALF_TURN;
218 PXfloat fd = (PXfloat)PXfabs(delta2);
219 if (fd >= barrier_tolerance) {
220 // ok, we are close to the barrier and at an acceptable angle - now nudge along
221 // work out pan of barrier
222
223 // we have our coordinate and a direction to shift in
224 PXfloat ang = bar->pan() * TWO_PI;
225
226 PXfloat cang = (PXfloat)PXcos(ang);
227 PXfloat sang = (PXfloat)PXsin(ang);
228
229 // Let's ignore the zero*something as it is always zero
230 M->actor_xyz.x += PXfloat2PXreal(NUDGE_DISTANCE * REAL_ONE * sang);
231 M->actor_xyz.z += PXfloat2PXreal(NUDGE_DISTANCE * REAL_ONE * cang);
232
233 return (__NUDGED); // we've avoided the hit
234 }
235 }
236 }
237 }
238 } // nudge for loop
239 } // if player
240
241 adjusted_pan = FLOAT_ZERO;
242 made_adjust = FALSE8;
243 normalAngle = 3 * FULL_TURN; // place holder to mean not set
244 int32 nFortKnox = 0;
245 uint32 nBarriers = (M->number_of_barriers + M->number_of_animating);
246
247 for (j = 0; j < nBarriers; j++) {
248 int32 b = Fetch_megas_barrier_number(j);
249 bar = session_barriers->Fetch_barrier(b);
250 ignoreBarrier[j] = 1;
251
252 if ((PXfloat)PXfabs(newy - bar->bottom()) > BARRIER_TOO_HIGH)
253 continue; // ignore abars that are now too high
254
255 __barrier_result result = Check_this_barrier(bar, newx, newz, oldx, oldz, bar_close, &ignoreThis);
256
257 // Ignore barrier culling isn't working - so do them all except animating barriers
258 ignoreThis = 0;
259
260 ignoreBarrier[j] = ignoreThis;
261 if (ignoreThis == 0)
262 nFortKnox++;
263
264 if (result != __OK)
265 return (result);
266 }
267 if ((!made_adjust) && (MS->player.player_status != RUNNING) && (MS->player.player_status != WALKING)) {
268 // didnt hit a normal barrier so check if we hit a stair or ladder barrier
269
270 // check for stair entry complience - oh yes
271 for (j = 0; j < num_stairs; j++) {
272 bar = &stairs[j].bar;
273
274 if (newy != bar->bottom())
275 continue; // not on our floor so continue with next
276
277 __barrier_result result = Check_this_barrier(bar, newx, newz, oldx, oldz, bar_close, &ignoreThis);
278 if (result != __OK)
279 return (result);
280 }
281 }
282
283 // if we hit a single corectable barrier then we can make that adjustment now
284 int32 repulsed = 0;
285 PXfloat destx = FLOAT_ZERO;
286 PXfloat destz = FLOAT_ZERO;
287
288 if (made_adjust) {
289 L->pan = adjusted_pan;
290
291 if (normalAngle < 2 * FULL_TURN) {
292 // Repulse the mega back a bit
293 PXfloat ang = normalAngle * TWO_PI;
294 PXfloat cang = (PXfloat)PXcos(ang);
295 PXfloat sang = (PXfloat)PXsin(ang);
296
297 // Let's ignore the zero*something as it is always zero
298 // the stored angle normalAngle is a normal angle pointing away
299 // from the barrier by 90 deg AND towards the players side of the
300 // barrier
301 repulsed = 1;
302 destx = M->actor_xyz.x + PXfloat2PXreal(REPULSE_DISTANCE * REAL_ONE * sang);
303 destz = M->actor_xyz.z + PXfloat2PXreal(REPULSE_DISTANCE * REAL_ONE * cang);
304 }
305 } else {
306 destx = newx;
307 destz = newz;
308 }
309
310 // Right so finally do a line intersection between the old position and the "final" new position
311 // old position is : oldx, oldz
312 // new position is : destx, destz
313 int32 hit = 0;
314
315 // Special treatment for the player
316 if (pl) {
317 for (j = 0; j < nBarriers; j++) {
318 int32 b = Fetch_megas_barrier_number(j);
319 bar = session_barriers->Fetch_barrier(b);
320
321 // Ignore barriers which are in the ignore list
322 if (ignoreBarrier[j] == 1)
323 continue;
324
325 hit = troute.Get_intersect(oldx, oldz, destx, destz, bar->x1(), bar->z1(), bar->x2(), bar->z2());
326
327 if (hit == 1) {
328 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,
329 bar->x1(), bar->z1(), bar->x2(), bar->z2());
330 break;
331 }
332 }
333 // Oh dear we went through a barrier
334 if (hit == 1)
335 return (__BLOCKED); // conflict, so finish
336 }
337
338 // The repulsed position looks good - so use it !
339 if (repulsed) {
340 M->actor_xyz.x = destx;
341 M->actor_xyz.z = destz;
342 }
343
344 // Return the correct values
345 if (made_adjust)
346 return (__CORRECTED);
347
348 // finally, if player is still looking good then do a check for him hitting other megas
349 if (pl) {
350 /*
351 /
352 mega /
353 position : mx, mz /
354 * /
355 /
356 /
357 /
358 /
359 /
360 /
361 /
362 /
363 / - his pan direction
364 #
365 player @ position : px, pz direction: pan
366
367 dx = PXsin( pan )
368 dz = PXcos( pan )
369
370 then the mega is on the left-hand side of the line (or on the line)
371 if ( (dz * ( mx - px )) <= ( dx * ( mz - pz )) )
372 else
373 // he is on the right-hand side of the line
374 */
375
376 static int32 total_adjusts = 0;
377
378 if ((!total_adjusts) && (MS->player.interact_selected) && (logic_structs[MS->player.cur_interact_id]->image_type == VOXEL)) {
379 // player is highlighting a mega
380
381 // check nearness
382
383 PXreal sub1, sub2;
384
385 sub1 = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.x - M->actor_xyz.x;
386 sub2 = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.z - M->actor_xyz.z;
387
388 // dist
389 PXreal distance = ((sub1 * sub1) + (sub2 * sub2));
390
391 // near
392 if (distance < (120 * 120)) {
393
394 if ((MS->player.cur_state.momentum != __FORWARD_1) && (MS->player.cur_state.momentum != __FORWARD_2))
395 return __OK;
396
397 PXreal dx = (PXreal)PXsin(L->pan * TWO_PI);
398 PXreal dz = (PXreal)PXcos(L->pan * TWO_PI);
399
400 PXreal mx = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.x;
401 PXreal mz = logic_structs[MS->player.cur_interact_id]->mega->actor_xyz.z;
402
403 if ((dz * (mx - M->actor_xyz.x)) <= (dx * (mz - M->actor_xyz.z))) {
404 // right
405 if ((distance > (50 * 50)) && (distance < (120 * 120)))
406 L->pan += 0.03f;
407 } else {
408 // left
409 if ((distance > (50 * 50)) && (distance < (120 * 120)))
410 L->pan -= 0.03f;
411 }
412
413 total_adjusts++;
414
415 return (__OK);
416 }
417 }
418 total_adjusts = 0; // reset
419 }
420 return (__OK);
421 }
422
Check_this_barrier(_route_barrier * bar,PXreal newx,PXreal newz,PXreal,PXreal,PXreal bar_close,int32 * ignoreThis)423 __barrier_result _game_session::Check_this_barrier(_route_barrier *bar, PXreal newx, PXreal newz, PXreal /* oldx */, PXreal /* oldz */, PXreal bar_close, int32 *ignoreThis) {
424 PXfloat delta;
425 PXfloat delta2;
426 PXfloat barrier_tolerance = BARRIER_TOLERANCE; // 1/8 of a turn = 45 degress
427 PXreal pdist, dist;
428 PXreal ignore_bar_close = IGNORE_BARRIER_CLOSE;
429
430 *ignoreThis = 1;
431
432 pdist = ((newx * bar->bcm().lpx()) + (newz * bar->bcm().lpz())) - bar->bcm().linedist();
433
434 if ((PXfloat)PXfabs(pdist) < bar_close) {
435 // we are near the plane so now we must check the end points
436 // check the left end of the line
437
438 dist = ((newx * bar->bcm().alpx()) + (newz * bar->bcm().alpz())) - bar->bcm().alinedist();
439
440 // check the right end
441 if (dist >= 0) {
442 dist = ((newx * bar->bcm().blpx()) + (newz * bar->bcm().blpz())) - bar->bcm().blinedist();
443
444 if (dist >= 0) {
445 *ignoreThis = 0;
446
447 // we are going to hit this barrier
448 // but, if the angle is narrow we can aquire the barriers pan and continue unmolested
449 delta = remainder(L->pan - bar->pan(), FULL_TURN, HALF_TURN);
450 delta2 = delta;
451
452 if (delta < -QUARTER_TURN)
453 delta2 += HALF_TURN;
454 if (delta > QUARTER_TURN)
455 delta2 -= HALF_TURN;
456 if (PXfabs(delta2) < barrier_tolerance) {
457 if (made_adjust)
458 return (__BLOCKED); // conflict, so finish
459
460 if ((delta > QUARTER_TURN) || (delta < -QUARTER_TURN)) {
461 adjusted_pan = remainder(bar->pan() + HALF_TURN, FULL_TURN, HALF_TURN);
462 } else {
463 adjusted_pan = bar->pan();
464 }
465 made_adjust = TRUE8;
466 if (adjusted_pan > L->pan) {
467 adjusted_pan += REPEL_TURN;
468 } else if (adjusted_pan < L->pan) {
469 adjusted_pan -= REPEL_TURN;
470 }
471 if (pdist > 0)
472 normalAngle = bar->pan() + QUARTER_TURN;
473 else if (pdist < 0)
474 normalAngle = bar->pan() - QUARTER_TURN;
475 } else {
476 // cant adjust
477 return (__BLOCKED);
478 }
479 } else
480 *ignoreThis = 1;
481 } else
482 *ignoreThis = 1;
483 } else if ((PXfloat)PXfabs(pdist) < ignore_bar_close) {
484 *ignoreThis = 0;
485 }
486
487 return __OK;
488 }
489
___init()490 void _barrier_handler::___init() {
491 _routing_slice *slice;
492 uint32 *num_bars;
493 uint32 len;
494
495 Zdebug("_barrier_handler");
496 Zdebug("\n+init _barrier_handler %s", MS->Fetch_session_name());
497
498 // load the raw barrier file for this session
499 // When clustered the session files have the base stripped
500 len = sprintf(temp_buf, "%s", PX_FILENAME_BARRIERLIST);
501 if (len > ENGINE_STRING_LEN)
502 Fatal_error("_barrier_handler::___init string len error");
503
504 Tdebug("barriers.txt", "%s", (const char *)temp_buf);
505 uint32 buf_hash = NULL_HASH;
506 uint32 cluster_hash = MS->Fetch_session_cluster_hash();
507 raw_barriers = (_linked_data_file *)private_session_resman->Res_open(temp_buf, buf_hash, MS->Fetch_session_cluster(), cluster_hash);
508
509 num_bars = (uint32 *)raw_barriers->Fetch_item_by_name("Count");
510
511 total_barriers = *(num_bars);
512
513 Tdebug("barriers.txt", "%d raw barriers", total_barriers);
514
515 // load in the routing wrapper
516 // When clustered the session files have the base stripped
517 len = sprintf(temp_buf, "%s", PX_FILENAME_ROUTING);
518 if (len > ENGINE_STRING_LEN)
519 Fatal_error("_barrier_handler::___init string len error");
520
521 Tdebug("barriers.txt", "%s", temp_buf);
522 buf_hash = NULL_HASH;
523 route_wrapper = (_linked_data_file *)private_session_resman->Res_open(temp_buf, buf_hash, MS->Fetch_session_cluster(), cluster_hash);
524
525 total_slices = route_wrapper->Fetch_number_of_items();
526
527 if (total_slices > MAX_slices)
528 Fatal_error("_barrier_handler::___init finds too many slices - %d but only %d allowed", total_slices, MAX_slices);
529
530 Tdebug("slice.txt", "%d routing levels", total_slices);
531
532 if (!total_slices) {
533 Zdebug("[%s]", (const char *)temp_buf);
534 Fatal_error("no parent routing levels (no parent boxes) engine cannot proceed");
535 }
536
537 uint32 j;
538 for (j = 0; j < total_slices; j++) {
539 slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(j);
540 Tdebug("slice.txt", "bottom %3.1f top %3.1f", slice->bottom, slice->top);
541 Tdebug("slice.txt", "%d parents", slice->num_parent_boxes);
542 }
543
544 // reset prop list for each
545 // fully reset abar systems
546 for (j = 0; j < MAX_slices; j++) {
547 anim_slices[j].num_props_in_slice = 0;
548 for (uint32 l = 0; l < MAX_parents_per_anim_slice; l++)
549 anim_slices[j].anim_parents[l] = 0; // unasigned pointer
550 }
551 for (j = 0; j < MAX_props; j++) {
552 anim_prop_info[j].barriers_per_state = 0;
553 anim_prop_info[j].total_states = 0;
554 }
555 for (j = 0; j < MAX_floors; j++) // reset the unassigned parents
556 anim_parent_table[j].num_props = 0;
557 parents_used = 0; // no parents have been assigned
558
559 Zdebug("anim bars");
560
561 Prepare_animating_barriers();
562
563 Zdebug("done barriers");
564 }
565
566 #define ADD_CHILD \
567 if (clist[j]->num_barriers) \
568 for (k = 0; k < clist[j]->num_barriers; k++) { \
569 bar = Fetch_barrier(clist[j]->barriers[k]); \
570 if (bar->bottom() == y) { \
571 if (barrier_mask) { \
572 if (MS->troute.LineIntersectsRect(mask, (int32)bar->x1(), (int32)bar->z1(), (int32)bar->x2(), (int32)bar->z2())) \
573 MS->troute.Add_barrier(bar); \
574 } else \
575 MS->troute.Add_barrier(bar); \
576 } \
577 }
578
579 #define EXPAND_ROUTE_BOX \
580 if (CHILDL < RBL) \
581 RBL = CHILDL; \
582 if (CHILDR > RBR) \
583 RBR = CHILDR; \
584 if (CHILDT < RBT) \
585 RBT = CHILDT; \
586 if (CHILDB > RBB) \
587 RBB = CHILDB; \
588 expanded_this_go++;
589
590 #define CHILDL clist[j]->left
591 #define CHILDR clist[j]->right
592 #define CHILDT clist[j]->back
593 #define CHILDB clist[j]->front
594 #define RBL rb.x1
595 #define RBR rb.x2
596 #define RBT rb.z1
597 #define RBB rb.z2
598
Form_parent_barrier_list(PXreal x,PXreal y,PXreal z)599 void _barrier_handler::Form_parent_barrier_list(PXreal x, PXreal y, PXreal z) {
600 // we are routing into a room - just get the parent barriers
601 _parent_box *endb;
602 uint32 parent_a, slice_a, k;
603 _route_barrier *bar;
604 uint32 *array;
605
606 endb = Fetch_parent_box_for_xyz(x, y, z, parent_a, slice_a);
607 if (!endb)
608 return; // will be because of between floor gap - not to worry
609
610 if (endb->num_barriers) {
611 array = (uint32 *)(((char *)endb) + (endb->barriers));
612 for (k = 0; k < endb->num_barriers; k++) {
613 bar = Fetch_barrier(array[k]);
614 MS->troute.Add_barrier(bar);
615 }
616 }
617 }
618
Form_route_barrier_list(PXreal x,PXreal y,PXreal z,PXreal x2,PXreal z2)619 void _barrier_handler::Form_route_barrier_list(PXreal x, PXreal y, PXreal z, PXreal x2, PXreal z2) {
620 // add all barriers to the prim route building system for the route x,z,x2,z2
621 // after this the route_manager can call the prim route builder for the final route to be made
622 // the restriction is that we can only route from one place to another within a single floor-rect/parent-box
623 // or
624 // from within one parent-box/floor-rect to an adjacent parent-box/floor-rect
625 // it is a higher level job to divide long routes up into rect to rect chunks before calling here
626 // but this is quite sensible anyway as we only want to be auto-routing across tiny areas at a time
627
628 _parent_box *startb;
629 _parent_box *endb;
630 _rect rb; // rb meaning 'Route-Box'
631 uint32 j;
632 _child_group *clist[MAX_child_groups_per_parent * 2];
633 uint32 total_childs = 0; // seperate total for safety
634 int32 expanded_this_go;
635 _route_barrier *bar;
636 uint32 k;
637 uint32 parent_a, parent_b;
638 uint32 slice_a, slice_b;
639
640 // which floors are the start and end positions in?
641 // list child boxes for each floor - ignoring the parent box concept?
642 // build route
643 // add parent boundaries for all parents that the final route box intersects - !?!
644
645 // find the parent box
646 // first, find _parent_box for start point and end points
647
648 startb = Fetch_parent_box_for_xyz(x, y, z, parent_a, slice_a);
649 endb = Fetch_parent_box_for_xyz(x2, y, z2, parent_b, slice_b);
650
651 if ((!startb) && (endb))
652 startb = endb; // no start but end
653 if ((!endb) && (startb))
654 endb = startb; // no end but start
655
656 if (!startb)
657 Fatal_error("_barrier_handler::Form_route_barrier_list start and end not on floor - %s", MS->Fetch_object_name(MS->Fetch_cur_id()));
658 // make a list of pointers to the child groups
659
660 if (startb != endb) { // oh dear - not going to allow this anymore
661 Form_parent_barrier_list(x2, y, z2);
662 Form_parent_barrier_list(x, y, z);
663 return;
664 }
665
666 Zdebug("%3.1f %3.1f %3.1f %3.1f", startb->back, startb->left, startb->front, startb->right);
667
668 if (startb->num_childgroups) {
669 for (j = 0; j < startb->num_childgroups; j++) {
670 if (total_childs == (MAX_child_groups_per_parent * 2))
671 Fatal_error("_barrier_handler::Form_route_barrier_list - clist ran out of space");
672 clist[total_childs++] = Fetch_child_box(startb, j);
673 }
674 }
675
676 // we now know the _parent_box that our start point is on - we therefore have the list of child boxes
677 // same or different?
678 if (startb != endb) { // different
679 Zdebug("different parent for end box");
680 if (endb->num_childgroups) {
681 Zdebug("adding %d child boxes for end point", endb->num_childgroups);
682 for (j = 0; j < endb->num_childgroups; j++) {
683 if (total_childs == (MAX_child_groups_per_parent * 2))
684 Fatal_error("_barrier_handler::Form_route_barrier_list - clist ran out of space");
685 clist[total_childs++] = Fetch_child_box(endb, j);
686 }
687 }
688 }
689
690 // ok, we now have a list of pointers to all the child groups relevant
691
692 // create the initial route box
693 if (x < x2) {
694 rb.x1 = x;
695 rb.x2 = x2;
696 } else {
697 rb.x1 = x2;
698 rb.x2 = x;
699 }
700 if (z < z2) {
701 rb.z1 = z;
702 rb.z2 = z2;
703 } else {
704 rb.z1 = z2;
705 rb.z2 = z;
706 }
707
708 // we now have our initial route box
709
710 // enter our main loop
711 do {
712 expanded_this_go = 0; // flag to say whether or no the route-box got expanded this loop
713
714 for (j = 0; j < total_childs; j++) {
715 if (clist[j]) {
716 // child not deleted
717
718 if (((CHILDR < RBL) || (CHILDL > RBR)) && ((CHILDB < RBT) || (CHILDT > RBB))) {
719 // child is wholly outside the route box - do nothing except prime the ELSE
720 } else if (((CHILDR >= RBL) && (CHILDL <= RBR)) && ((CHILDB >= RBT) && (CHILDT <= RBB))) {
721 // child is wholly inside route box - add it and delete child
722 ADD_CHILD
723 clist[j] = NULL; // delete the child now it has been absorbed
724 } else if (((RBR >= CHILDL) && (RBL <= CHILDR)) && ((RBT >= CHILDT) && (RBB <= CHILDB))) {
725 // route box is wholly inside child box - expand route box, add and delete child
726 ADD_CHILD
727 clist[j] = NULL; // delete the child now it has been absorbed
728 EXPAND_ROUTE_BOX
729 } else {
730 if ((CHILDL > RBL) && (CHILDL < RBR) && ((CHILDT > RBT) && (CHILDT < RBB))) {
731 // child top/left is within route box - expand route box, add and delete child
732 ADD_CHILD
733 clist[j] = NULL; // delete the child now it has been absorbed
734 EXPAND_ROUTE_BOX
735 } else if ((CHILDR > RBL) && (CHILDR < RBR) && ((CHILDT > RBT) && (CHILDT < RBB))) {
736 // child top/right is within route box - expand route box, add and delete child
737 ADD_CHILD
738 clist[j] = NULL; // delete the child now it has been absorbed
739 EXPAND_ROUTE_BOX
740 } else if ((CHILDL > RBL) && (CHILDL < RBR) && ((CHILDB > RBT) && (CHILDB < RBB))) {
741 // child bottom/left is within route box - expand route box, add and delete child
742 ADD_CHILD
743 clist[j] = NULL; // delete the child now it has been absorbed
744 EXPAND_ROUTE_BOX
745 } else if ((CHILDR > RBL) && (CHILDR < RBR) && ((CHILDB > RBT) && (CHILDB < RBB))) {
746 // child bottom/right is within route box - expand route box, add and delete child
747 ADD_CHILD
748 clist[j] = NULL; // delete the child now it has been absorbed
749 EXPAND_ROUTE_BOX
750 } else {
751 // we must check for our route line intersecting a horizontal and vertical child box edge
752 }
753 }
754 }
755 }
756
757 // if this loop we did not expand the route_box then we quit this DO-WHILE loop
758 if (!expanded_this_go)
759 break;
760 } while (1);
761
762 // if there are two parent boxes we must add the parent barriers from each to the list
763 if (startb != endb) {
764 // add both parent box barriers in
765 uint32 *array;
766
767 if (startb->num_barriers) {
768 array = (uint32 *)(((char *)startb) + (startb->barriers));
769 for (k = 0; k < startb->num_barriers; k++) {
770 bar = Fetch_barrier(array[k]);
771 MS->troute.Add_barrier(bar);
772 }
773 }
774 if (endb->num_barriers) {
775 array = (uint32 *)(((char *)endb) + (endb->barriers));
776 for (k = 0; k < endb->num_barriers; k++) {
777 bar = Fetch_barrier(array[k]);
778 MS->troute.Add_barrier(bar);
779 }
780 }
781 } else { // route lies within a single floor - so draw a box around it
782 _route_barrier newbar;
783
784 // left hand barrier
785 newbar.x1(startb->left);
786 newbar.z1(startb->back);
787 newbar.x2(startb->left);
788 newbar.z2(startb->front);
789 MS->troute.Add_barrier(&newbar);
790
791 // right hand barrier
792 newbar.x1(startb->right);
793 newbar.z1(startb->back);
794 newbar.x2(startb->right);
795 newbar.z2(startb->front);
796 MS->troute.Add_barrier(&newbar);
797
798 // top barrier
799 newbar.x1(startb->left);
800 newbar.z1(startb->back);
801 newbar.x2(startb->right);
802 newbar.z2(startb->back);
803 MS->troute.Add_barrier(&newbar);
804
805 // bottom barrier
806 newbar.x1(startb->left);
807 newbar.z1(startb->front);
808 newbar.x2(startb->right);
809 newbar.z2(startb->front);
810 MS->troute.Add_barrier(&newbar);
811 }
812 }
813
Fetch_parent_num_on_slice_y(uint32 requested_parent,PXreal y)814 _parent_box *_barrier_handler::Fetch_parent_num_on_slice_y(uint32 requested_parent, PXreal y) {
815 // fetch the parent of the number passed for a given y level
816 // ie 0 means first, 1 means second, etc
817 // this is called by the plan-viewer which just keeps asking for the next one until we say there are no more
818 // by passing back a 0 instead of a pointer to a parent
819 static _routing_slice *slice;
820 uint32 cur_slice = 0;
821
822 // first time in so compute the slice
823 if (!requested_parent) {
824 while (1) {
825 slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(cur_slice);
826
827 if ((y >= slice->bottom) && (y < slice->top))
828 break;
829
830 // safety
831 cur_slice++;
832 if (cur_slice == total_slices) // if so then must be last slice :O
833 Fatal_error("Fetch_parent_num_on_slice_y ran out of slices");
834
835 // next
836 slice++;
837 }
838 }
839
840 // ok, we have the slice
841 // return the parent of the requested number - or, 0 if there is no more
842
843 // reached total?
844 if (requested_parent == slice->num_parent_boxes)
845 return (0);
846
847 // simply return the pointer
848
849 return ((_parent_box *)(((uint8 *)slice) + slice->parent_boxes[requested_parent]));
850 }
851
Fetch_barrier(uint32 num)852 _route_barrier *_barrier_handler::Fetch_barrier(uint32 num) {
853 // return a pointer to numbered barrier
854 _route_barrier *bar;
855
856 assert(num < total_barriers);
857
858 if (num >= total_barriers)
859 Fatal_error("illegal barrier request %d", num);
860
861 bar = (_route_barrier *)raw_barriers->Fetch_item_by_name("Data");
862
863 return &bar[num];
864 }
865
Fetch_parent_box_for_xyz(PXreal x,PXreal y,PXreal z,uint32 & par_num,uint32 & slice_num)866 _parent_box *_barrier_handler::Fetch_parent_box_for_xyz(PXreal x, PXreal y, PXreal z, uint32 &par_num, uint32 &slice_num) {
867 // return a pointer to the parent box of a point in world space
868 // returns 0 if the point does not lie within a parent box
869
870 _routing_slice *slice = NULL;
871 _parent_box *parent = NULL;
872
873 // find correct slice according to height
874 // fetch first
875
876 slice_num = 0;
877
878 while (1) {
879 slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(slice_num);
880
881 if ((y >= slice->bottom) && (y < slice->top))
882 break;
883
884 // safety
885 slice_num++;
886 if (slice_num == total_slices) { // if so then must be last slice :O
887 Fatal_error("_barrier_handler::Fetch_parent_box_for_xyz ran out of slices: object [%s] (%3.1f %3.1f %3.1f) has an "
888 "illegal marker",
889 MS->Fetch_object_name(MS->Fetch_cur_id()), x, y, z);
890 }
891 // next
892 slice++;
893 }
894
895 // ok, we found the right y slice
896 // now find the right parent box
897 if (!slice->num_parent_boxes)
898 Fatal_error("_barrier_handler::Fetch_parent_box_for_xyz slice has no parent boxes");
899
900 for (par_num = 0; par_num < slice->num_parent_boxes; par_num++) {
901 parent = (_parent_box *)(((uint8 *)slice) + slice->parent_boxes[par_num]);
902
903 // do we lie within the box?
904 if ((x > parent->left) && (x < parent->right) && (z > parent->back) && (z < parent->front)) {
905 return (parent);
906 }
907 }
908
909 return (0);
910 }
911
Prepare_megas_route_barriers(bool8 pl)912 void _game_session::Prepare_megas_route_barriers(bool8 pl) {
913 // see which parent box we're owned by
914 // if different from previous fetch all the barriers for the new parent
915 // this system is custom for the player object - routing megas use their own system
916 // this routine fecthes the 'special' player only line-of-sight barriers too
917
918 _parent_box *par = 0;
919 _child_group *pchild;
920 uint32 total_childs;
921 uint32 j, k;
922 uint32 *list;
923 _route_barrier *bar;
924 uint32 parent_number;
925 _routing_slice *slice;
926 PXreal x, y, z;
927
928 x = M->actor_xyz.x;
929 y = floor_def->Return_true_y(M->actor_xyz.y);
930 z = M->actor_xyz.z;
931
932 // on previous slice?
933 slice = (_routing_slice *)session_barriers->route_wrapper->Fetch_item_by_number(M->cur_slice);
934 if ((y >= slice->bottom) && (y < slice->top) && (M->cur_parent))
935 if ((x > M->cur_parent->left) && (x < M->cur_parent->right) && (z > M->cur_parent->back) && (z < M->cur_parent->front)) {
936 // nothing has changed
937 Prepare_megas_abarriers(M->cur_slice, M->par_number);
938
939 // player should have added the barriers of stood megas
940 if (pl)
941 Fetch_mega_barriers_for_player();
942
943 return;
944 }
945
946 M->cur_slice = 0;
947 while (1) {
948 slice = (_routing_slice *)session_barriers->route_wrapper->Fetch_item_by_number(M->cur_slice);
949 if ((y >= slice->bottom) && (y < slice->top))
950 break;
951
952 // safety
953 M->cur_slice++;
954 if (M->cur_slice == session_barriers->total_slices) { // if so then must be last slice :O
955 M->cur_slice--;
956 slice = (_routing_slice *)session_barriers->route_wrapper->Fetch_item_by_number(M->cur_slice);
957 break;
958 }
959 }
960 // ok, we found the right y slice
961 // now find the right parent box
962 if (!slice->num_parent_boxes)
963 Fatal_error("Prepare_megas_route_barriers slice has no parent boxes");
964
965 for (parent_number = 0; parent_number < slice->num_parent_boxes; parent_number++) {
966 par = (_parent_box *)(((uint8 *)slice) + slice->parent_boxes[parent_number]);
967
968 // do we lie within the box?
969 if ((x > par->left) && (x < par->right) && (z > par->back) && (z < par->front)) {
970 break; // found
971 }
972 }
973
974 if (parent_number == slice->num_parent_boxes) {
975 // not on a legal position - can happen
976 M->cur_parent = 0; // null pointer
977 M->number_of_barriers = 0;
978 M->number_of_nudge = 0;
979 M->number_of_animating = 0;
980 return;
981 }
982
983 // has a parent box different from the current one been found?
984 {
985 // new one
986 M->cur_parent = par;
987 M->par_number = parent_number;
988
989 // reset list of barrier ids
990 M->number_of_barriers = 0;
991 M->number_of_animating = 0;
992
993 // firstly, drag out the parents bounding barriers if it has any
994 if (par->num_barriers) {
995 list = (uint32 *)((uint8 *)par + par->barriers);
996 // get all the barriers
997 for (j = 0; j < par->num_barriers; j++) {
998 // fetch each barrier and check that its bottom edge is on the floor - otherwise we ignore it
999 bar = session_barriers->Fetch_barrier(*(list));
1000 if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
1001 // ok, this barrier is on the floor so we add it to our list
1002 M->barrier_list[M->number_of_barriers++] = *(list++);
1003 }
1004 }
1005 }
1006
1007 if (pl)
1008 M->number_of_nudge = 0; // reset now - in case there are none
1009
1010 // now player only specials
1011 if ((pl) && (par->num_specials)) {
1012 #ifdef VERBOSE
1013 Zdebug("getting player specials");
1014 #endif
1015
1016 list = (uint32 *)((uint8 *)par + par->specials);
1017 // get all the barriers
1018 for (j = 0; j < par->num_specials; j++) {
1019 // fetch each barrier and check that its bottom edge is on the floor - otherwise we ignore it
1020 bar = session_barriers->Fetch_barrier(*(list));
1021
1022 if (bar->material() == VIEW_FIELD) {
1023 if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
1024 // ok, this barrier is on the floor so we add it to our list
1025 M->barrier_list[M->number_of_barriers++] = *(list++);
1026 }
1027 } else if (bar->material() >= LEFT_NUDGE) {
1028 if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
1029 // ok, this barrier is on the floor so we add it to our list
1030 M->nudge_list[M->number_of_nudge++] = *(list++);
1031 }
1032 } else {
1033 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(),
1034 bar->x2(), bar->z1(), bar->z2());
1035 }
1036 }
1037 }
1038
1039 // find out have many child boxes this parent has
1040 total_childs = session_barriers->Fetch_number_of_child_boxes(par);
1041
1042 for (j = 0; j < total_childs; j++) {
1043 pchild = session_barriers->Fetch_child_box(par, j);
1044
1045 for (k = 0; k < pchild->num_barriers; k++) {
1046 bar = session_barriers->Fetch_barrier(pchild->barriers[k]);
1047 if (bar->bottom() == slice->bottom) { // M->actor_xyz.y)
1048 M->barrier_list[M->number_of_barriers++] = pchild->barriers[k];
1049 }
1050 }
1051 }
1052 }
1053
1054 // now build the animating barrier list - regardless of whether or not the parent has changed
1055 Prepare_megas_abarriers(M->cur_slice, M->par_number);
1056
1057 if (M->number_of_barriers + M->number_of_animating > MAX_bars)
1058 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);
1059
1060 if (M->number_of_nudge > MAX_bars)
1061 Fatal_error("too many player nudge barriers");
1062 }
1063
Prepare_animating_barriers()1064 void _barrier_handler::Prepare_animating_barriers() {
1065 // the nightmare that is animating barriers
1066 // search through all prop animations getting out the animating barriers - checking for duplicates
1067
1068 #define MAX_anim_barriers 400
1069 uint32 j;
1070 uint16 barrier_table[MAX_anim_barriers];
1071 uint32 total_anim_bars = 0;
1072 _route_barrier *bar;
1073 _routing_slice *slice;
1074 _parent_box *parent;
1075 uint32 cur_slice = 0;
1076 uint32 l, f, pbar_num;
1077 uint32 abar_index = 0;
1078
1079 Tdebug("anim_barriers.txt", "Preparing animating barriers");
1080
1081 for (j = 0; j < MS->prop_anims->Fetch_number_of_items(); j++) {
1082 Tdebug("anim_barriers.txt", "\n%d %s", j, MS->prop_anims->Fetch_items_name_by_number(j));
1083
1084 _animating_prop *index;
1085 _animation_entry *anim;
1086
1087 index = (_animating_prop *)MS->prop_anims->Fetch_item_by_number(j);
1088
1089 Tdebug("anim_barriers.txt", " has %d anims", index->num_anims);
1090
1091 // loop through all looking for our named anim
1092 if (index->num_anims) {
1093 // get the prop number
1094
1095 for (uint32 k = 0; k < index->num_anims; k++) {
1096 anim = (_animation_entry *)(((char *)index) + index->anims[k]);
1097 Tdebug("anim_barriers.txt", " '%s' - %d frames", (((char *)index) + anim->name), anim->num_frames);
1098
1099 if (anim->num_barriers_per_frame) {
1100 Tdebug("anim_barriers.txt", " has %d anim barriers per frame", anim->num_barriers_per_frame);
1101 uint16 *bars = (uint16 *)(((char *)index) + anim->offset_barriers);
1102
1103 for (uint32 i = 0; i < (uint32)(anim->num_barriers_per_frame * anim->num_frames); i++) {
1104 if (bars[i] != 0xffff) {
1105 // check each barrier for duplication and add in to correct slice, parent list
1106
1107 for (l = 0; l < total_anim_bars; l++) {
1108 if (barrier_table[l] == bars[i]) {
1109 Tdebug("anim_barriers.txt", " %d in list already - index %d", bars[i], i);
1110 break; // found this bar
1111 }
1112 }
1113 // i is barrier index
1114
1115 bar = Fetch_barrier(bars[i]);
1116
1117 if (l == total_anim_bars) { // didnt find in list
1118 Tdebug("anim_barriers.txt", " new barrier %d x%3.2f y%3.2f z%3.2f", bars[i], bar->x1(), bar->bottom(),
1119 bar->z1());
1120
1121 barrier_table[total_anim_bars++] = (uint16)bars[i]; // write the bar down
1122
1123 if (total_anim_bars == MAX_anim_barriers)
1124 Fatal_error("Prepare_animating_barriers finds too many barriers "
1125 "for scratch table");
1126 }
1127 cur_slice = 0;
1128
1129 do {
1130 slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(cur_slice);
1131
1132 if ((bar->bottom() >= slice->bottom) && (bar->bottom() < slice->top))
1133 break;
1134
1135 cur_slice++;
1136 } while (cur_slice != total_slices);
1137
1138 if (cur_slice == total_slices) { // if so then must be last slice :O
1139 Tdebug("anim_barriers.txt", " **ran out of slices :O\n");
1140 } else {
1141 Tdebug("anim_barriers.txt", " exists on slice %d", cur_slice);
1142
1143 // check legality of number of parents
1144 if (slice->num_parent_boxes > MAX_parents_per_anim_slice)
1145 Fatal_error("prepare anim barriers finds too many parents in slice "
1146 "- %d parents",
1147 slice->num_parent_boxes);
1148
1149 int32 prop_number =
1150 MS->objects->Fetch_item_number_by_name((const char *)MS->prop_anims->Fetch_items_name_by_number(j));
1151
1152 if (prop_number == -1) {
1153 Tdebug("anim_barriers.txt", " !!associated prop [%s] not a game object - so ignoring",
1154 (const char *)MS->prop_anims->Fetch_items_name_by_number(j));
1155 } else {
1156 // now find parent the barrier would belong to
1157 for (f = 0; f < slice->num_parent_boxes; f++) {
1158 Tdebug("anim_barriers.txt", " check parent %d", f);
1159
1160 parent = (_parent_box *)(((uint8 *)slice) + slice->parent_boxes[f]);
1161
1162 // do we lie within the box?
1163 if ((bar->x1() > parent->left) && (bar->x1() < parent->right) && (bar->z1() > parent->back) &&
1164 (bar->z1() < parent->front)) {
1165 char *props_name = (char *)MS->prop_anims->Fetch_items_name_by_number(j);
1166 uint32 props_number = MS->objects->Fetch_item_number_by_name(props_name);
1167
1168 if (!anim_slices[cur_slice].anim_parents[f]) {
1169 anim_slices[cur_slice].anim_parents[f] = &anim_parent_table[parents_used++];
1170 Tdebug("anim_barriers.txt", " new aparent");
1171 }
1172
1173 pbar_num = anim_slices[cur_slice].anim_parents[f]->num_props;
1174
1175 uint32 n;
1176 for (n = 0; n < pbar_num; n++)
1177 if (anim_slices[cur_slice].anim_parents[f]->prop_number[n] == props_number)
1178 break;
1179
1180 if (n == pbar_num) { // new
1181 anim_slices[cur_slice].anim_parents[f]->num_props++;
1182
1183 if (pbar_num == MAX_props_per_parent)
1184 Fatal_error("too many props in "
1185 "parent - max = %d",
1186 MAX_props_per_parent);
1187
1188 Tdebug("anim_barriers.txt", " found - slice %d, parent %d "
1189 "[%d bars so far], prop [%s, %d] state "
1190 "%d\n",
1191 cur_slice, f, anim_slices[cur_slice].anim_parents[f]->num_props, props_name,
1192 props_number, anim->frames[i / anim->num_barriers_per_frame]);
1193
1194 anim_slices[cur_slice].anim_parents[f]->prop_number[pbar_num] = (uint8)props_number;
1195 }
1196 break;
1197 }
1198 }
1199 if (f == slice->num_parent_boxes)
1200 Tdebug("anim_barriers.txt", " !!barrier not located within a parent box!!\n");
1201 }
1202 }
1203 } else
1204 Tdebug("anim_barriers.txt", " !!barrier is type 0xffffffff");
1205 }
1206 } else
1207 Tdebug("anim_barriers.txt", " 0 anim bars");
1208 }
1209 }
1210 }
1211
1212 // now reverse engineer the target lists
1213 for (j = 0; j < total_slices; j++) {
1214 Tdebug("anim_barriers.txt", " slice %d", j);
1215
1216 for (uint32 k = 0; k < MAX_parents_per_anim_slice; k++) {
1217 if (!anim_slices[j].anim_parents[k])
1218 Tdebug("anim_barriers.txt", " par %d free", k);
1219 else {
1220 Tdebug("anim_barriers.txt", " parent %d has %d animating props", k, anim_slices[j].anim_parents[k]->num_props);
1221 for (uint32 i = 0; i < anim_slices[j].anim_parents[k]->num_props; i++)
1222 Tdebug("anim_barriers.txt", " prop num %d", anim_slices[j].anim_parents[k]->prop_number[i]);
1223 }
1224 }
1225 }
1226
1227 Tdebug("anim_barriers.txt", "\n\n\n\n\n--------preparing prop slice format---------------\n");
1228
1229 uint32 total_states, i;
1230
1231 // now compute the special prop table for run-time LOS injection
1232 // first reset special prop fixed list
1233 for (j = 0; j < MAX_props; j++)
1234 anim_prop_info[j].barriers_per_state = 0; // do it here so it can double up as 0 being an unused entry
1235
1236 for (j = 0; j < MS->prop_anims->Fetch_number_of_items(); j++) {
1237 Tdebug("anim_barriers.txt", "\n**%d %s", j, MS->prop_anims->Fetch_items_name_by_number(j));
1238 _animating_prop *index;
1239 _animation_entry *anim;
1240
1241 index = (_animating_prop *)MS->prop_anims->Fetch_item_by_number(j);
1242
1243 // loop through all looking for our named anim
1244 if (index->num_anims) {
1245 // got a prop
1246 // it has anims
1247 // is it a prop with animating barriers?
1248
1249 // get first anim
1250 anim = (_animation_entry *)(((char *)index) + index->anims[0]);
1251
1252 // does it have anim barriers
1253 if (anim->num_barriers_per_frame) {
1254 // ok, we're on
1255
1256 Tdebug("anim_barriers.txt", " has %d anims and %d per frame", index->num_anims, anim->num_barriers_per_frame);
1257
1258 // reset our total number of states for this prop counter
1259 total_states = 0;
1260
1261 // find the first legal barrier in this anim
1262 uint16 *bars = (uint16 *)(((char *)index) + anim->offset_barriers);
1263 i = 0;
1264 while ((bars[i] == 0xffff) && (i < (uint32)(anim->num_barriers_per_frame * anim->num_frames)))
1265 i++;
1266
1267 // better make sure the anim has a legal barrier - if not then assume the prop is well knackered and leave
1268 // it out of the anim barrier system
1269 if (i < (uint32)(anim->num_barriers_per_frame * anim->num_frames)) {
1270 // get our chosen sample barrier
1271 bar = Fetch_barrier(bars[i]);
1272
1273 // now compute slice for sample barrier
1274 cur_slice = 0;
1275 do {
1276 slice = (_routing_slice *)route_wrapper->Fetch_item_by_number(cur_slice);
1277 if ((bar->bottom() >= slice->bottom) && (bar->bottom() < slice->top))
1278 break;
1279 cur_slice++;
1280 } while (cur_slice != total_slices);
1281
1282 // check for not on a slice - not good
1283 if (cur_slice == total_slices) { // if so then must be last slice :O
1284 Tdebug("anim_barriers.txt", " **ran out of slices :O\n");
1285 } else {
1286 Tdebug("anim_barriers.txt", " sample bar puts prop in slice %d", cur_slice);
1287
1288 // get the prop number
1289 uint32 prop_number = MS->objects->Fetch_item_number_by_name((const char *)MS->prop_anims->Fetch_items_name_by_number(j));
1290
1291 // gotta check for anims with no equivelent game objects
1292 if (prop_number != 0xffffffff) {
1293 Tdebug("anim_barriers.txt", " listing as prop number %d", anim_slices[cur_slice].num_props_in_slice);
1294 // ok, add the prop to the slices list of props
1295 anim_slices[cur_slice].prop_list[anim_slices[cur_slice].num_props_in_slice++] = (uint8)prop_number;
1296
1297 if (anim_slices[cur_slice].num_props_in_slice >= MAX_props)
1298 Fatal_error("form anim barrier list found too many props in the slice");
1299
1300 // set number of barriers per frame for this prop
1301 anim_prop_info[prop_number].barriers_per_state = anim->num_barriers_per_frame; // set from our sample first anim
1302
1303 // now loop through all the anims filling in the state table
1304 // in theory, having done this, there will be entries for each state referenced
1305 for (uint32 k = 0; k < index->num_anims; k++) {
1306 // get anim k
1307 anim = (_animation_entry *)(((char *)index) + index->anims[k]);
1308
1309 // get anims list of barriers
1310 uint16 *barriers = (uint16 *)(((char *)index) + anim->offset_barriers);
1311
1312 // go through each frame/state
1313 for (uint32 c = 0; c < anim->num_frames; c++) {
1314 // get state
1315 uint32 state = anim->frames[c];
1316
1317 // keep computing the total number of states for this prop
1318 if (state > total_states)
1319 total_states = state;
1320
1321 // for each state go through all the barriers per frame/state
1322 for (i = 0; i < anim->num_barriers_per_frame; i++) {
1323 // gotta check for funny illegal barriers
1324 if (barriers[(c * anim->num_barriers_per_frame) + i] != 0xffff) {
1325 // legal barrier
1326 barrier_table[(state * anim->num_barriers_per_frame) + i] =
1327 (uint16)barriers[(c * anim->num_barriers_per_frame) + i];
1328 } else {
1329 // dodgy barrier
1330 // setting to barrier 0 but this is not a proper
1331 // solution
1332 barrier_table[(state * anim->num_barriers_per_frame) + i] = 0;
1333 }
1334 }
1335 }
1336 }
1337 // ok, we've set up the anim barriers for this prop
1338
1339 Tdebug("anim_barriers.txt", " prop [%s] highest state %d, %d bars per state",
1340 (const char *)MS->prop_anims->Fetch_items_name_by_number(j), total_states,
1341 anim_prop_info[prop_number].barriers_per_state);
1342
1343 // note down total states
1344 anim_prop_info[prop_number].total_states = (uint8)(total_states + 1);
1345
1346 // create space for table
1347 Tdebug("anim_barriers.txt", "prop %d needs %d uint16's", prop_number,
1348 (total_states + 1) * anim_prop_info[prop_number].barriers_per_state);
1349
1350 if (abar_index >= MAX_prop_abars)
1351 Fatal_error("too many animating barriers - current max = %d", MAX_prop_abars);
1352
1353 // move the barrier table
1354 memcpy(&prop_abar_table[abar_index], barrier_table,
1355 (sizeof(uint16) * ((total_states + 1) * anim_prop_info[prop_number].barriers_per_state)));
1356
1357 anim_prop_info[prop_number].barrier_list = &prop_abar_table[abar_index];
1358
1359 abar_index += ((total_states + 1) * anim_prop_info[prop_number].barriers_per_state);
1360
1361 } else { // if prop number legal
1362 Tdebug("anim_barriers.txt", " prop has no object - ignoring");
1363 }
1364 }
1365 }
1366 }
1367 }
1368 }
1369
1370 Tdebug("anim_barriers.txt", " ");
1371
1372 for (j = 0; j < MS->Fetch_number_of_objects(); j++)
1373 if (anim_prop_info[j].barriers_per_state) {
1374 Tdebug("anim_barriers.txt", "prop %d", j);
1375 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),
1376 anim_prop_info[j].total_states, anim_prop_info[j].barriers_per_state);
1377 Tdebug("anim_barriers.txt", "total %d", anim_prop_info[j].barriers_per_state * (anim_prop_info[j].total_states));
1378 for (uint16 k = 0; k < anim_prop_info[j].barriers_per_state * (anim_prop_info[j].total_states); k++)
1379 Tdebug("anim_barriers.txt", "%d %d", k, anim_prop_info[j].barrier_list[k]);
1380 }
1381
1382 Tdebug("anim_barriers.txt", "\nDone");
1383 }
1384
Get_anim_barriers(uint32 n,uint32 * oThisCubesBarriers,uint32 slice)1385 uint32 _barrier_handler::Get_anim_barriers(uint32 n, uint32 *oThisCubesBarriers, uint32 slice) {
1386 // gives you all the 'current' anim barriers on an ENTIRE slice
1387 // used by LOS, planview,
1388 uint32 prop_id;
1389 uint32 prop_state;
1390 uint32 bars_per_state;
1391 uint32 bar_index;
1392 uint16 *bars;
1393 uint32 j, k;
1394
1395 // how many props in this slice
1396 uint32 num_props = anim_slices[slice].num_props_in_slice; // prop_list.GetNoItems();
1397
1398 for (j = 0; j < num_props; j++) {
1399 // get id of prop
1400 prop_id = anim_slices[slice].prop_list[j];
1401
1402 // get prop state
1403 prop_state = MS->prop_state_table[prop_id];
1404
1405 // get number of barriers per state
1406 bars_per_state = anim_prop_info[prop_id].barriers_per_state;
1407
1408 // index into barrier list to first barrier for this state
1409 bar_index = (prop_state * bars_per_state);
1410
1411 bars = (uint16 *)&anim_prop_info[prop_id].barrier_list[0];
1412 bars += bar_index;
1413
1414 for (k = 0; k < bars_per_state; k++) {
1415 if (*(bars) >= total_barriers)
1416 Fatal_error("Get_anim_barriers - illegal barrier request %d", *(bars));
1417
1418 oThisCubesBarriers[n++] = (uint32) * (bars++);
1419 }
1420 }
1421
1422 return n;
1423 }
1424
Prepare_megas_abarriers(uint32 slice_number,uint32 parent_number)1425 void _game_session::Prepare_megas_abarriers(uint32 slice_number, uint32 parent_number) {
1426 // fetch abars for the current parent ONLY
1427 M->number_of_animating = 0;
1428 uint32 num_props;
1429 uint32 prop_id;
1430 uint32 prop_state;
1431 uint32 bars_per_state;
1432 uint32 bar_index;
1433 uint16 *bars;
1434 uint32 k;
1435
1436 if (!session_barriers->anim_slices[slice_number].anim_parents[parent_number])
1437 return; // parent has none at all
1438
1439 num_props = session_barriers->anim_slices[slice_number].anim_parents[parent_number]->num_props;
1440
1441 for (uint32 i = 0; i < num_props; i++) {
1442 // yup - our parent does have animating props
1443
1444 // get prop id on this parent
1445 prop_id = session_barriers->anim_slices[slice_number].anim_parents[parent_number]->prop_number[i];
1446
1447 // get prop state
1448 prop_state = prop_state_table[prop_id];
1449
1450 // get number of barriers per state
1451 bars_per_state = session_barriers->anim_prop_info[prop_id].barriers_per_state;
1452
1453 // index into barrier list to first barrier for this state
1454 bar_index = (prop_state * bars_per_state);
1455
1456 bars = (uint16 *)&session_barriers->anim_prop_info[prop_id].barrier_list[0];
1457 bars += bar_index;
1458
1459 for (k = 0; k < bars_per_state; k++)
1460 M->barrier_list[M->number_of_barriers + M->number_of_animating++] = (uint32) * (bars++);
1461 }
1462 }
1463
Fetch_mega_barriers_for_player()1464 void _game_session::Fetch_mega_barriers_for_player() {
1465 // find all the megas on our floor
1466 // then add in barriers for each of them that is stood
1467 // add the barriers on the end of the anim barrier list which MUST have already been computed
1468 }
1469
1470 } // End of namespace ICB
1471