1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Source: r:/prj/cit/src/RCS/physics.c $
21 * $Revision: 1.259 $
22 * $Author: xemu $
23 * $Date: 1994/11/10 16:05:25 $
24 *
25 */
26
27 #define __PHYSICS_SRC
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32
33 #include "ai.h"
34 #include "combat.h"
35 #include "criterr.h"
36 #include "cyber.h"
37 #include "cybmem.h"
38 #include "cybstrng.h"
39 #include "damage.h"
40 #include "diffq.h" // for time limit
41 #include "drugs.h"
42 #include "effect.h"
43 #include "faketime.h"
44 #include "framer8.h"
45 #include "froslew.h"
46 #include "gamestrn.h"
47 #include "grenades.h"
48 #include "hud.h"
49 #include "ice.h"
50 #include "invent.h"
51 #include "loops.h"
52 #include "lvldata.h"
53 #include "map.h"
54 #include "mapflags.h"
55 #include "mfdext.h"
56 #include "musicai.h"
57 #include "objbit.h"
58 #include "objects.h"
59 #include "objsim.h"
60 #include "objprop.h"
61 #include "objuse.h"
62 #include "otrip.h"
63 #include "physics.h"
64 #include "physunit.h"
65 #include "player.h"
66 #include "render.h"
67 #include "sfxlist.h"
68 #include "tilename.h"
69 #include "tools.h"
70 #include "trigger.h"
71 #include "wares.h"
72 #include "weapons.h"
73 #include "mouselook.h"
74
75 /*
76 #include <fastmat.h>
77 #include <faceleth.h>
78 #include <btfunc.h>
79 */
80
81 #define EXPAND_FIX(x) fix_int(x), fix_frac(x)
82
83 #define sqr(fixval) (fix_mul(fixval, fixval))
84
85 // INTERNAL PROTOTYPES
86 // --------------------
87 uchar safety_net_wont_you_back_me_up(ObjID oid);
88 void add_edms_delete(int ph);
89 void edms_delete_go(void);
90 void get_phys_state(int ph, State *new_state, ObjID id);
91 void physics_zero_all_controls(void);
92 errtype compare_locs(void);
93 void physics_set_relax(int axis, uchar relax);
94 void relax_axis(int axis);
95 errtype collide_objects(ObjID collision, ObjID victim, int bad);
96 void terrain_object_collide(physics_handle src, ObjID target);
97 errtype run_cspace_collisions(ObjID obj, ObjID exclude, ObjID exclude2);
98 void state_to_objloc(State *s, ObjLoc *l);
99 uchar get_phys_info(int ph, fix *list, int cnt);
100 fix ID2radius(ObjID id);
101
102 // STANDARD MODELS
103 // ---------------
104
105 #define STANDARD_HARDNESS fix_make(15, 0)
106 #define STANDARD_ROUGHNESS fix_make(5, 0)
107 #define STANDARD_PEP fix_make(5, 0)
108 #define DEFAULT_SIZE (FIX_UNIT / 2)
109 #define STANDARD_HEIGHT fix_make(0, 0xbd00)
110
111 Robot standard_robot = {STANDARD_MASS, DEFAULT_SIZE, STANDARD_HARDNESS, STANDARD_PEP, STANDARD_GRAVITY, FALSE};
112
113 Pelvis standard_pelvis = {STANDARD_MASS, DEFAULT_SIZE, STANDARD_HARDNESS, STANDARD_PEP, STANDARD_GRAVITY,
114 STANDARD_HEIGHT, FALSE};
115
116 fix standard_corner[4] = {0, 0, 0, 0};
117 Dirac_frame standard_dirac = {
118 STANDARD_MASS, STANDARD_HARDNESS, STANDARD_ROUGHNESS, STANDARD_GRAVITY,
119 #ifdef HMMMM
120 standard_corner, standard_corner, standard_corner, standard_corner, standard_corner,
121 standard_corner, standard_corner, standard_corner, standard_corner, standard_corner,
122 #endif
123 };
124
125 extern ObjID physics_handle_id[];
126 extern int physics_handle_max;
127
128 #define check_up(num)
129
130 cams *motion_cam = NULL; // what to move, default null is the default camera
131
132 // CONTROLS
133 // --------
134
135 byte player_controls[CONTROL_BANKS][DEGREES_OF_FREEDOM] = {
136 {0, 0, 0, 0, 0, 0},
137 {0, 0, 0, 0, 0, 0},
138 {0, 0, 0, 0, 0, 0},
139 {0, 0, 0, 0, 0, 0}
140 };
141
142 extern errtype (*state_generators[])(ObjID id, int x, int y, ObjLocState *ret);
143 long old_ticks;
144
145 // Collision callback testing....
146 void cit_collision_callback(physics_handle C, physics_handle V, int32_t bad, int32_t DATA1, int32_t DATA2, fix location[3]);
147 void cit_awol_callback(physics_handle caller);
148 void cit_sleeper_callback(physics_handle caller);
149 void cit_autodestruct_callback(physics_handle caller);
150
151 // mapping from physics controls to camera controls
152 int ctrl2cam[DEGREES_OF_FREEDOM] = {EYE_X, EYE_Y, EYE_Z, EYE_H, EYE_P, EYE_B};
153
154 #define SLEW_SCALE_N 16
155 #define SLEW_SCALE_D 100
156
157 #define MAX_EDMS_DELETE_OBJS 50
158
159 #ifdef EDMS_SAFETY_NET
160 short safety_fail_oid = -1;
161 uchar safety_fail_count = 0;
162 #define SECRET_NET_OUT_P(x, y) (x > 0x20)
163 #define TOGGLEABLE_SNET
164 #endif
165
166 uchar safety_net_on = TRUE;
167 short curr_edms_del = 0;
168 short edms_delete_queue[MAX_EDMS_DELETE_OBJS];
169
safety_net_wont_you_back_me_up(ObjID oid)170 uchar safety_net_wont_you_back_me_up(ObjID oid) {
171 obj_move_to(oid, &objs[oid].loc, TRUE);
172 if (safety_fail_oid == oid) {
173 safety_fail_oid = -1;
174 return FALSE;
175 }
176 if (oid == PLAYER_OBJ)
177 safety_fail_oid = oid;
178 else if (safety_fail_oid == -1)
179 safety_fail_oid = oid;
180 safety_fail_count = 3;
181 return TRUE;
182 }
183
add_edms_delete(int ph)184 void add_edms_delete(int ph) {
185 int i = 0;
186 uchar bad = FALSE;
187 extern char *get_object_lookname(ObjID id, char use_string[], int sz);
188
189 for (i = 0; i < curr_edms_del; i++)
190 if (edms_delete_queue[i] == ph)
191 bad = TRUE;
192
193 if (ph == -1)
194 bad = TRUE;
195
196 if (!bad) {
197 edms_delete_queue[curr_edms_del] = ph;
198 curr_edms_del++;
199 objs[physics_handle_id[ph]].info.ph = -1;
200 physics_handle_id[ph] = OBJ_NULL;
201 }
202 }
203
edms_delete_go()204 void edms_delete_go() {
205 int i;
206 for (i = 0; i < curr_edms_del; i++) {
207 if (edms_delete_queue[i] != -1)
208 EDMS_kill_object(edms_delete_queue[i]);
209 edms_delete_queue[i] = -1;
210 }
211 curr_edms_del = 0;
212 }
213
get_phys_state(int ph,State * new_state,ObjID id)214 void get_phys_state(int ph, State *new_state, ObjID id) {
215 char use_mod = EDMS_ROBOT;
216 if (id != OBJ_NULL) {
217 use_mod = ObjProps[OPNUM(id)].physics_model;
218 #ifdef DIRAC_EDMS
219 // This is hacked on account of the player having 2 physics models.
220 // We may want to take an unused critter slot like the lifter bot to be the dirac-player
221 // like sonic is our pelvis-player.
222 if (id == PLAYER_OBJ)
223 use_mod = (global_fullmap->cyber) ? EDMS_DIRAC : EDMS_PELVIS;
224 #endif
225 }
226 switch (use_mod) {
227 case EDMS_PELVIS:
228 EDMS_get_pelvic_viewpoint(ph, new_state);
229 break;
230 case EDMS_DIRAC:
231 EDMS_get_Dirac_frame_viewpoint(ph, new_state);
232 break;
233 default:
234 EDMS_get_state(ph, new_state);
235 break;
236 }
237 }
238
physics_zero_all_controls()239 void physics_zero_all_controls() { LG_memset(player_controls, 0, sizeof(player_controls)); }
240
physics_set_player_controls(int bank,byte xvel,byte yvel,byte zvel,byte xyrot,byte yzrot,byte xzrot)241 errtype physics_set_player_controls(int bank, byte xvel, byte yvel, byte zvel, byte xyrot, byte yzrot, byte xzrot) {
242 if (xvel != CONTROL_NO_CHANGE)
243 player_controls[bank][CONTROL_XVEL] = xvel;
244 if (yvel != CONTROL_NO_CHANGE)
245 player_controls[bank][CONTROL_YVEL] = yvel;
246 if (zvel != CONTROL_NO_CHANGE)
247 player_controls[bank][CONTROL_ZVEL] = zvel;
248 if (xyrot != CONTROL_NO_CHANGE)
249 player_controls[bank][CONTROL_XYROT] = xyrot;
250 if (yzrot != CONTROL_NO_CHANGE)
251 player_controls[bank][CONTROL_YZROT] = yzrot;
252 if (xzrot != CONTROL_NO_CHANGE)
253 player_controls[bank][CONTROL_XZROT] = xzrot;
254 return OK;
255 }
256
physics_set_one_control(int bank,int num,byte val)257 errtype physics_set_one_control(int bank, int num, byte val) {
258 if (val != CONTROL_NO_CHANGE)
259 player_controls[bank][num] = val;
260 return OK;
261 }
262
physics_get_one_control(int bank,int num,byte * val)263 errtype physics_get_one_control(int bank, int num, byte *val) {
264 *val = player_controls[bank][num];
265 return OK;
266 }
267
268 int old_x = -1, old_y = -1, old_lev = -1;
269 char old_bits = 0;
270 extern uchar decon_count;
271 extern uchar in_deconst;
272 extern uchar in_peril;
273
274 #define TUNNEL_CONTROL_MAX fix_make(0x8, 0)
275 #define MATCHBOX_SPEED fix_make(0x3F, 0)
276
277 // The concept here is that if you want something to happen when the player switches
278 // square, put it here...
279
compare_locs(void)280 errtype compare_locs(void) {
281 extern void expose_player(byte damage, ubyte type, ushort hlife);
282 extern void check_hazard_regions(MapElem *);
283 MapElem *newElem, *oldElem;
284 extern int score_playing;
285
286 if ((old_x != PLAYER_BIN_X) || (old_y != PLAYER_BIN_Y) || (old_lev != player_struct.level)) {
287 newElem = MAP_GET_XY(PLAYER_BIN_X, PLAYER_BIN_Y);
288 oldElem = MAP_GET_XY(old_x, old_y);
289
290 // Change music
291 if (music_on) {
292 if (!global_fullmap->cyber) {
293 in_deconst = me_bits_deconst(newElem);
294 if (!in_deconst)
295 decon_count = 0;
296 in_peril = me_bits_peril(newElem);
297 if (old_bits != me_bits_music(newElem)) {
298 fade_into_location(PLAYER_BIN_X, PLAYER_BIN_Y);
299 old_bits = me_bits_music(newElem);
300 }
301 }
302 }
303
304 // Abort physics if bad karma
305 if (physics_running && time_passes && (me_tiletype(newElem) == TILE_SOLID)) {
306 physics_running = FALSE;
307 critical_error(CRITERR_EXEC | 2);
308 }
309
310 // Look for traps
311 if (time_passes)
312 check_entrance_triggers(old_x, old_y, PLAYER_BIN_X, PLAYER_BIN_Y);
313
314 check_hazard_regions(newElem);
315
316 old_x = PLAYER_BIN_X;
317 old_y = PLAYER_BIN_Y;
318 old_lev = player_struct.level;
319 }
320
321 return (OK);
322 }
323
324 uchar control_relax[DEGREES_OF_FREEDOM];
325
physics_set_relax(int axis,uchar relax)326 void physics_set_relax(int axis, uchar relax) { control_relax[axis] = relax; }
327
relax_axis(int axis)328 void relax_axis(int axis) {
329 switch (axis) {
330 case CONTROL_XZROT:
331 player_set_lean(0, player_struct.leany);
332 break;
333 case CONTROL_YZROT:
334 player_set_eye(0);
335 break;
336 }
337 }
338
339 static ubyte crouch_controls[NUM_POSTURES] = {0, 6, 10};
340
341 #define CSPACE_COLLIDE_DIST 0xD0
342 #define CSPACE_FAR_COLLIDE_DIST 0x120
343
344 #define MAX_PITCH_RATE (FIXANG_PI / 4)
345 #define MAX_LEAN_RATE 400
346
347 #define ITER_OBJSPECS(pmo, objspec) \
348 for (pmo = (objspec[OBJ_SPEC_NULL]).id; pmo != OBJ_SPEC_NULL; pmo = objspec[pmo].next)
349
350 // Yow, we have GOT to be able to make this faster/better... -- Xemu
run_cspace_collisions(ObjID obj,ObjID exclude,ObjID exclude2)351 errtype run_cspace_collisions(ObjID obj, ObjID exclude, ObjID exclude2) {
352 ObjRefID oref = me_objref(MAP_GET_XY(OBJ_LOC_BIN_X(objs[obj].loc), OBJ_LOC_BIN_Y(objs[obj].loc)));
353 short use_dist;
354 while (oref != OBJ_REF_NULL) {
355 ObjID oid = objRefs[oref].obj;
356 ObjLoc l1 = objs[oid].loc;
357 ObjLoc l2 = objs[obj].loc;
358 switch (ID2TRIP(oid)) {
359 case CYBERTOG1_TRIPLE:
360 case CYBERTOG2_TRIPLE:
361 case CYBERTOG3_TRIPLE:
362 use_dist = CSPACE_FAR_COLLIDE_DIST;
363 break;
364 default:
365 use_dist = CSPACE_COLLIDE_DIST;
366 break;
367 }
368 if ((oid != obj) && (oid != exclude) && (oid != exclude2) && (objs[oid].obclass != CLASS_PHYSICS)) {
369 // This really ought to take PX into account!
370 if ((abs(l1.x - l2.x) < use_dist) && (abs(l1.y - l2.y) < use_dist) &&
371 ((abs(l1.z - l2.z) << SLOPE_SHIFT_D) < use_dist)) {
372 obj_cspace_collide(oid, obj);
373 }
374 }
375 oref = objRefs[oref].next;
376 }
377 return (OK);
378 }
379
380 #define PLAYER_JIGGLE_THRESHOLD 0x3 // this is in objsys coords
381
382 #define MAX_SPRINT (fix_make(25, 0))
383 #define MAX_JOG (fix_make(8, 0))
384 #define MAX_BOOSTER (fix_make(50, 0))
385 #define SKATE_ALPHA_CUTOFF (fix_make(8, 0))
386 #define MAX_BOOSTER_ALPHA (fix_make(40, 0))
387
388 extern void physics_set_relax(int axis, uchar relax);
389
390 // Takes a physics state and converts it into an Objloc
391 // externed in objsim.c
state_to_objloc(State * s,ObjLoc * l)392 void state_to_objloc(State *s, ObjLoc *l) {
393 l->x = obj_coord_from_fix(s->X);
394 l->y = obj_coord_from_fix(s->Y);
395 l->z = obj_height_from_fix(s->Z);
396 l->h = obj_angle_from_phys(s->alpha);
397 #ifdef WHY_DOESNT_THIS_WORK
398 l->p = obj_angle_from_phys(s->beta);
399 l->b = obj_angle_from_phys(s->gamma);
400 #endif
401 }
402
403 #define NO_DEFAULT_FORWARD_IN_CSPACE
404
405 #define CYB_VEL_DELTA 32
406 #define CYB_VEL_DELTA2 16
407 ubyte old_head = 0, old_pitch = 0;
408 short last_deltap = 0, last_deltah = 0;
409
physics_run(void)410 errtype physics_run(void) {
411 int i;
412 extern int avail_memory(int debug_src);
413
414 uchar update = FALSE;
415 int deltat = player_struct.deltat;
416 fix plr_y, plr_z, time_diff;
417 fix plr_alpha;
418 State new_state;
419 uchar some_move = FALSE;
420 extern int fire_kickback;
421 extern uchar hack_takeover;
422 static long kickback_time = 0; // i bet this static will someday bite our butts, like save/rest mid kickback?
423 #ifdef EDMS_SAFETY_NET
424 uchar allow_move = TRUE;
425 #endif
426
427 // Run the mouse look
428 mouse_look_physics();
429
430 // Here we are computing the values of the player's controls
431 // from the values of the original control banks. The value
432 // of each control is the average of its non-zero control
433 // values from each control bank, or zero if all are zero.
434 for (i = 0; i < DEGREES_OF_FREEDOM; i++) {
435 int b, n = 0;
436 short control = 0;
437 for (b = 0; b < CONTROL_BANKS; b++)
438 if (player_controls[b][i] != 0) {
439 control += player_controls[b][i];
440 n++;
441 }
442 if (n > 0) {
443 some_move = TRUE; // should really do the n!=1 for 2 and 4 as shift too
444 if (n > 1) {
445 control /= n;
446 }
447 } else if (control_relax[i]) {
448 relax_axis(i);
449 }
450 player_struct.controls[i] = control;
451 }
452 update = some_move; // well, set one of them only once
453 if (physics_running && time_passes) {
454 int i;
455 ObjID oid;
456 int damp;
457 fix plr_side;
458 fix plr_lean;
459 ObjSpecID osid;
460 {
461 fix crouch = fix_make(0, player_struct.lean_filter_state);
462 damp = 3 * sqr(STANDARD_HEIGHT - crouch) / sqr(STANDARD_HEIGHT) + 1;
463 }
464 osid = objPhysicss[0].id;
465 while (osid != OBJ_SPEC_NULL) {
466 // clear the terrain flag
467
468 if (objPhysicss[osid].p3.x > 0)
469 objPhysicss[osid].p3.x--;
470
471 // clear the collision flag
472 if (objPhysicss[osid].p3.y > 0)
473 objPhysicss[osid].p3.y--;
474
475 osid = objPhysicss[osid].next;
476 }
477
478 if (motionware_mode == MOTION_SKATES && damp > 1)
479 damp--;
480 // Here' s where we do leaning.
481 if (player_struct.foot_planted) {
482 plr_y = plr_alpha = plr_side = 0;
483 physics_set_relax(CONTROL_XZROT, FALSE);
484 } else {
485 byte leanx = player_struct.leanx;
486 byte ycntl = player_struct.controls[CONTROL_YVEL];
487 short maxlean = (int)(SPRINT_CONTROL_THRESHOLD - abs(ycntl)) * CONTROL_MAX_VAL / SPRINT_CONTROL_THRESHOLD;
488 plr_side = fix_make(player_struct.controls[CONTROL_XVEL], 0) / 7 / damp;
489 plr_alpha = fix_make(player_struct.controls[CONTROL_XYROT], 0) / -5; // / damp;
490 if (ycntl <= SPRINT_CONTROL_THRESHOLD)
491 plr_y = ycntl * MAX_JOG / SPRINT_CONTROL_THRESHOLD;
492 else
493 plr_y = (ycntl - SPRINT_CONTROL_THRESHOLD) * (MAX_SPRINT - MAX_JOG) /
494 (CONTROL_MAX_VAL - SPRINT_CONTROL_THRESHOLD) +
495 MAX_JOG;
496 plr_y /= damp;
497 physics_set_relax(CONTROL_XZROT, abs((short)leanx) > maxlean);
498 }
499 if (player_struct.drug_status[DRUG_REFLEX] > 0 && !global_fullmap->cyber) {
500 // Increase some controls to reflect smaller timestep
501 plr_y = plr_y << 2;
502 plr_alpha = plr_alpha << 2;
503 plr_side = plr_side << 2;
504 }
505 switch (motionware_mode) {
506 case MOTION_BOOST: {
507 plr_y = MAX_BOOSTER;
508 // whoop whoop hardcoded version number.
509 if (player_struct.hardwarez[CPTRIP(MOTION_HARD_TRIPLE)] < 3) {
510 if (plr_alpha < 0)
511 plr_alpha = -MAX_BOOSTER_ALPHA;
512 if (plr_alpha > 0)
513 plr_alpha = MAX_BOOSTER_ALPHA;
514 }
515 break;
516 }
517 case MOTION_SKATES:
518 plr_y *= 2;
519 if (plr_y > 3 * MAX_SPRINT / 2) {
520 plr_y = 3 * MAX_SPRINT / 2;
521 } else if (plr_y < -MAX_SPRINT) {
522 plr_y = -MAX_SPRINT;
523 }
524 plr_side >>= 2;
525 if (abs(plr_alpha) > SKATE_ALPHA_CUTOFF) {
526 if (plr_alpha > 0)
527 plr_alpha = SKATE_ALPHA_CUTOFF + (plr_alpha - SKATE_ALPHA_CUTOFF) / 2;
528 else
529 plr_alpha = -(SKATE_ALPHA_CUTOFF + (-plr_alpha - SKATE_ALPHA_CUTOFF) / 2);
530 }
531
532 break;
533 }
534
535 time_diff = fix_make(deltat, 0); // do this here for constant length kickback hack
536
537 if (time_diff > fix_make(CIT_CYCLE, 0) / MIN_FRAME_RATE)
538 time_diff = fix_make(CIT_CYCLE, 0) / MIN_FRAME_RATE;
539
540 if (player_struct.controls[CONTROL_XZROT] != 0) {
541 short delta = player_struct.controls[CONTROL_XZROT] * MAX_LEAN_RATE / CONTROL_MAX_VAL;
542 int leanx = player_struct.leanx;
543 leanx = lg_min(CONTROL_MAX_VAL, lg_max(leanx + delta * deltat / CIT_CYCLE, -CONTROL_MAX_VAL));
544 player_set_lean(leanx, player_struct.leany);
545 }
546 if (player_struct.controls[CONTROL_YZROT] != 0) {
547 extern int player_get_eye_fixang(void);
548 extern void player_set_eye_fixang(int);
549 int delta = player_struct.controls[CONTROL_YZROT] * MAX_PITCH_RATE / CONTROL_MAX_VAL;
550 int eye = player_get_eye_fixang();
551 if (player_struct.drug_status[DRUG_REFLEX] > 0 && !global_fullmap->cyber)
552 delta <<= 2;
553 eye = lg_min(FIXANG_PI / 2, lg_max(eye + delta * deltat / CIT_CYCLE, -FIXANG_PI / 2));
554 player_set_eye_fixang(eye);
555 }
556
557 plr_lean = fix_make((int)player_struct.leanx, 0) / 3;
558 if (player_struct.controls[CONTROL_ZVEL] > 0) {
559 extern void activate_jumpjets(fix * x, fix * y, fix * z);
560 extern uchar jumpjets_active;
561
562 player_set_posture(POSTURE_STAND);
563 plr_z = fix_make(player_struct.controls[CONTROL_ZVEL], 0);
564 activate_jumpjets(&plr_side, &plr_y, &plr_z);
565 jumpjets_active = plr_z < 0;
566 } else {
567 extern uchar jumpjets_active;
568 plr_z = fix_make(player_struct.controls[CONTROL_ZVEL], 0); /* /3/damp; */
569 jumpjets_active = FALSE;
570 }
571
572 if (global_fullmap->cyber) {
573 MapElem *pme = MAP_GET_XY(PLAYER_BIN_X, PLAYER_BIN_Y);
574 if (me_light_flr(pme)) {
575 if (plr_y > TUNNEL_CONTROL_MAX)
576 plr_y = TUNNEL_CONTROL_MAX;
577 }
578 // make controls non-linear.
579 plr_side = fix_mul(plr_side, abs(plr_side)) / 16;
580 plr_alpha = fix_mul(plr_alpha, abs(plr_alpha)) / 16;
581
582 #ifdef NO_DEFAULT_FORWARD_IN_CSPACE
583 if (QUESTVAR_GET(CYBER_DIFF_QVAR) > 1)
584 plr_z += fix_make(QUESTVAR_GET(CYBER_DIFF_QVAR) * 5, 0);
585 #endif
586
587 // Effects of turbo, multiply all movement axes by 4
588 if (cspace_effect_times[CS_TURBO_EFF]) {
589 plr_y = plr_y << 1;
590 plr_z = plr_z << 1;
591 plr_side = plr_side << 1;
592 }
593 #ifdef MATCHBOX_SUPPORT
594 else if (cspace_effect_times[CS_MATCHBOX_EFF]) {
595 plr_z = MATCHBOX_SPEED;
596 }
597 #endif
598 }
599 if (!global_fullmap->cyber && player_struct.drug_status[CPTRIP(GENIUS_DRUG_TRIPLE)] > 0) {
600 // Reverse!
601 plr_alpha = -plr_alpha;
602 plr_side = -plr_side;
603 plr_lean = -plr_lean;
604 }
605
606 #ifdef DIRAC_EDMS
607 if (global_fullmap->cyber) {
608 // printf("EDMS_control_Dirac_frame\n");
609 EDMS_control_Dirac_frame(PLAYER_PHYSICS, plr_z, plr_alpha + fix_make(mlook_vel_x, 5),
610 plr_y - fix_make(mlook_vel_y, 5), plr_side);
611 } else
612 #endif
613 // printf("EDMS_control_pelvis %i %i %i %i %i %i %i\n", PLAYER_PHYSICS, plr_y, plr_alpha, plr_side,
614 // plr_lean, plr_z, crouch_controls[player_struct.posture]);
615 EDMS_control_pelvis(PLAYER_PHYSICS, plr_y, plr_alpha, plr_side, plr_lean, plr_z,
616 crouch_controls[player_struct.posture]);
617
618 #ifdef SOLITON_HACK_REFLEX
619 if (player_struct.drug_status[DRUG_REFLEX] > 0 && !global_fullmap->cyber)
620 EDMS_soliton_vector((time_diff / CIT_CYCLE) >> 2);
621 else
622 #endif
623 EDMS_soliton_vector(time_diff / CIT_CYCLE);
624
625 edms_delete_go();
626
627 if (--safety_fail_count == 0)
628 safety_fail_oid = -1;
629 for (i = 0; i <= physics_handle_max; i++) // all ph
630 {
631 if ((oid = physics_handle_to_id(i)) != OBJ_NULL) // valid ph, get oid
632 {
633 ObjLoc newloc;
634
635 newloc = objs[oid].loc;
636
637 EDMS_get_state(objs[oid].info.ph, &new_state);
638 state_to_objloc(&new_state, &newloc);
639
640 if ((oid == PLAYER_OBJ) && global_fullmap->cyber) {
641 ubyte new_head, new_pitch; //, new_bank;
642 short new_deltah, new_deltap;
643 State cyber_state;
644 extern uchar new_cyber_orient;
645
646 get_phys_state(objs[PLAYER_OBJ].info.ph, &cyber_state, PLAYER_OBJ);
647
648 new_head = obj_angle_from_phys(cyber_state.alpha);
649 new_pitch = obj_angle_from_phys(cyber_state.beta);
650
651 new_deltah = abs(new_head - old_head);
652 new_deltap = abs(new_pitch - old_pitch);
653
654 if (((new_deltah < CYB_VEL_DELTA) && (new_deltap < CYB_VEL_DELTA)) || new_cyber_orient ||
655 ((abs(last_deltah - new_deltah) < CYB_VEL_DELTA2) &&
656 (abs(last_deltap - new_deltap) < CYB_VEL_DELTA2))) {
657 old_head = new_head;
658 old_pitch = new_pitch;
659 last_deltah = last_deltap = 0;
660
661 if (new_cyber_orient)
662 new_cyber_orient = FALSE;
663 } else {
664 last_deltah = new_deltah;
665 last_deltap = new_deltap;
666 }
667 }
668
669 // See if we should snap the player out of his
670 // reverie, either hack camera or automap induced.
671 if (oid == PLAYER_OBJ) {
672 if (hack_takeover &&
673 (some_move || (abs(newloc.x - objs[oid].loc.x) + abs(newloc.y - objs[oid].loc.y) +
674 abs(newloc.z - objs[oid].loc.z) >
675 PLAYER_JIGGLE_THRESHOLD)))
676 hack_camera_relinquish();
677 }
678
679 #ifdef EDMS_SAFETY_NET
680 #ifdef TOGGLEABLE_SNET
681 if (safety_net_on)
682 #endif
683 {
684 if (me_tiletype(MAP_GET_XY(OBJ_LOC_BIN_X(newloc), OBJ_LOC_BIN_Y(newloc))) == TILE_SOLID) {
685 safety_net_wont_you_back_me_up(oid);
686 allow_move = FALSE;
687 } else if (new_state.Z < fix_from_map_height(me_height_flr(
688 MAP_GET_XY(OBJ_LOC_BIN_X(newloc), OBJ_LOC_BIN_Y(newloc))))) {
689 if (safety_net_wont_you_back_me_up(oid))
690 allow_move = FALSE;
691 else {
692 if (objs[oid].obclass == CLASS_CRITTER) {
693 newloc = objs[oid].loc;
694 newloc.z += 3;
695 safety_fail_oid = -1;
696 allow_move = TRUE;
697 } else {
698 add_edms_delete(objs[oid].info.ph);
699 allow_move = FALSE; // just plain sit here and lose, eh?
700 }
701 }
702 }
703 }
704
705 if (allow_move)
706 obj_move_to(oid, &newloc, FALSE);
707 else
708 allow_move = TRUE;
709 #else
710 obj_move_to(oid, &newloc, FALSE);
711 #endif
712 }
713 }
714 } else if (some_move) { // what is going on here... ah-ha, we objslew.. no wrong
715 for (i = 0; i < DEGREES_OF_FREEDOM; i++)
716 if (player_struct.controls[i] != 0)
717 fr_camera_slewcam(motion_cam, ctrl2cam[i], player_struct.controls[i] * SLEW_SCALE_N / SLEW_SCALE_D);
718 }
719 old_ticks = *tmd_ticks;
720 if (update || hack_takeover)
721 chg_set_flg(_current_3d_flag);
722 if (physics_running && global_fullmap->cyber) {
723 ObjSpecID specid;
724 // check for the player
725 run_cspace_collisions(PLAYER_OBJ, OBJ_NULL, OBJ_NULL);
726
727 // check for all slow projectiles
728 ITER_OBJSPECS(specid, objPhysicss) {
729 run_cspace_collisions(objPhysicss[specid].id, PLAYER_OBJ, objPhysicss[specid].owner);
730 }
731 }
732 compare_locs();
733 return (OK);
734 }
735
736 #ifdef NOT_YET // later, dude
737
738 #ifdef WACKY_OLD_TERR_FUNC
739
740 /// ---------------------------------------------------
741 /// HERE COMES THE TERRAIN FUNCTION
742
743 /// 9/20 ML I ain't tellin' you a secret...
744 /// I ain't tellin' you goodBIYEYE...
745
746 /* ---------------------------------
747 HAQ ALERT! HAQ ALERT!
748 Ok, oftimes we're squaring small numbers.
749 So we're going to use our own special
750 8-24 intermediate fixpoint representation to
751 store the squares
752 -------------------------------- */
753
754 typedef fix wacky;
755
756 // Our own special 8-24 fixmul
757 wacky wacky_mul(fix a, fix b);
758 #pragma aux wacky_mul = "imul edx" \
759 "shr eax,8" \
760 "shl edx,24" \
761 "or eax,edx" parm[eax][edx] modify[eax edx];
762
763 wacky wacky_div(wacky a, wacky b);
764 #pragma aux wacky_div = "mov edx,eax" \
765 "sar edx,8" \
766 "shl eax,24" \
767 "idiv ebx" parm[eax][ebx] modify[eax edx];
768
769 typedef fix pt3d[3];
770
771 #define PTARGS(pt) fix_float((pt)[0]), fix_float((pt)[1]), fix_float((pt)[2])
772
773 #define dotprod(vec1, vec2, result) \
774 { \
775 fix *v1 = (vec1); \
776 fix *v2 = (vec2); \
777 (result) = 0; \
778 result += fix_mul(*(v1++), *(v2++)); \
779 result += fix_mul(*(v1++), *(v2++)); \
780 result += fix_mul(*(v1++), *(v2++)); \
781 }
782
783 #define wsqr(fixval) (wacky_mul(fixval, fixval))
784 #define magsquared(vec, res) \
785 { \
786 fix *v1 = (vec); \
787 (res) = 0; \
788 (res) += wsqr(*(v1++)); \
789 (res) += wsqr(*(v1++)); \
790 (res) += wsqr(*(v1++)); \
791 }
792
vec_equal(fix * v1,fix * v2)793 uchar vec_equal(fix *v1, fix *v2) {
794 if (*(v1++) == *(v2++) && *(v1++) == *(v2++) && *(v1++) == *(v2++))
795 return TRUE;
796 else
797 return FALSE;
798 }
799
800 #define wacky2fix(m2) (m2 >> 8)
801 #define fix2wacky(m) (m << 8)
802 #define wacky_float(w) fix_float(wacky2fix(w))
803
804 #define NORMAL_X 0
805 #define NORMAL_Y 1
806 #define NORMAL_Z 2
807
compute_normal_code(pt3d norm)808 int compute_normal_code(pt3d norm) {
809 if (abs(norm[0]) > abs(norm[1])) {
810 if (abs(norm[0]) > abs(norm[2]))
811 return NORMAL_X;
812 else
813 return NORMAL_Z;
814 } else {
815 if (abs(norm[1]) > abs(norm[2]))
816 return NORMAL_Y;
817 else
818 return NORMAL_Z;
819 }
820 }
821
822 #define PHYS_SPEW(x, y)
823
824 #define crossprod(v1, v2, out) \
825 { \
826 fix *a1 = (v1); \
827 fix *a2 = (v1); \
828 fix *b1 = (v2); \
829 fix *b2 = (v2); \
830 fix *o = (out); \
831 fix z = fix_mul(*(v1), (*++b2)) - fix_mul((*++a2), *(v2)); \
832 *(o++) = fix_mul((*++a1), (*++b2)) - fix_mul((*++a2), (*++b1)); \
833 *(o++) = fix_mul((*++a1), *(v2)) - fix_mul(*(v1), (*++b1)); \
834 *(o++) = z; \
835 }
836
project_onto_facelet(pt3d in,pt3d out,pt3d flet[NUM_POINTS])837 fix project_onto_facelet(pt3d in, pt3d out, pt3d flet[NUM_POINTS]) {
838 g3s_vector topt;
839 fix dp;
840 int i;
841 g3s_vector norm = *(g3s_vector *)(flet[NORM_IDX]);
842 g3_vec_sub(&topt, (g3s_vector *)in, (g3s_vector *)(flet[0]));
843 dp = g3_vec_dotprod(&topt, &norm);
844 g3_vec_scale(&norm, &norm, dp);
845 // Subtract out normal component
846 g3_vec_sub((g3s_vector *)out, (g3s_vector *)in, &norm);
847 PHYS_SPEW(DSRC_PHYSICS_Terrain,
848 ("Projection onto facelet: %q %q %q --> %q %q %q\nproj =%q\n", PTARGS(in), PTARGS(out), fix_float(dp)));
849 return dp;
850 }
851
852 int normcode_indices[3][2] = {{1, 2}, {0, 2}, {0, 1}};
853
854 // Takes a point on the plane of a facelet, and computes
855 // the distance from the projection to the facelet. Returns
856 // zero if the point projects onto the interior of the facelet.
facelet_distance_sq_4points(pt3d pt,pt3d flet[NUM_POINTS],uchar normcode)857 fix facelet_distance_sq_4points(pt3d pt, pt3d flet[NUM_POINTS], uchar normcode) {
858 fix best_dsq = FIX_MAX; // minimum distance squared
859 int best_vert = -1;
860 fix *best_edge;
861 fix *cprod_edge;
862 fix cprod_msq;
863 pt3d edgen;
864 pt3d cprod;
865 pt3d edgep;
866 pt3d topt; // vertex to point;
867 {
868 pt3d *vert = flet;
869 fix result;
870
871 g3_vec_sub((g3s_vector *)topt, (g3s_vector *)pt, (g3s_vector *)vert);
872 result = g3_vec_mag((g3s_vector *)topt);
873 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q dsq %d best_dsq %d\n", PTARGS(topt), result, best_dsq));
874 if (result < best_dsq) {
875 best_dsq = result;
876 best_vert = 0;
877 }
878 vert++;
879 g3_vec_sub((g3s_vector *)topt, (g3s_vector *)pt, (g3s_vector *)vert);
880 result = g3_vec_mag((g3s_vector *)topt);
881 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q dsq %d best_dsq %d\n", PTARGS(topt), result, best_dsq));
882 if (result < best_dsq) {
883 best_dsq = result;
884 best_vert = 1;
885 }
886 vert++;
887 g3_vec_sub((g3s_vector *)topt, (g3s_vector *)pt, (g3s_vector *)vert);
888 result = g3_vec_mag((g3s_vector *)topt);
889 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q dsq %d best_dsq %d\n", PTARGS(topt), result, best_dsq));
890 if (result < best_dsq) {
891 best_dsq = result;
892 best_vert = 2;
893 }
894 vert++;
895 g3_vec_sub((g3s_vector *)topt, (g3s_vector *)pt, (g3s_vector *)vert);
896 result = g3_vec_mag((g3s_vector *)topt);
897 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q dsq %d best_dsq %d\n", PTARGS(topt), result, best_dsq));
898 if (result < best_dsq) {
899 best_dsq = result;
900 best_vert = 3;
901 }
902 }
903 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Closest vertex %d\n", best_vert));
904 {
905 fix a1, a2, b1, b2, p1, p2, c1, c2;
906 int i1, i2;
907 fix d;
908 int nx = (best_vert + 1) & 0x3;
909 int pr = (best_vert + 3) & 0x3;
910 fix *ep = edgep;
911 fix *en = edgen;
912 fix *tp = topt;
913 fix *p = pt;
914 fix *vert = &flet[best_vert][0];
915 fix *prev = &flet[pr][0];
916 fix *next = &flet[nx][0];
917 if (vec_equal(prev, vert)) {
918 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Caught multiple on prev\n"));
919 pr = (pr + 3) & 0x3;
920 prev = flet[pr];
921 }
922 if (vec_equal(next, vert)) {
923 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Caught multiple on next\n"));
924 nx = (nx + 1) & 0x3;
925 next = flet[nx];
926 }
927 g3_vec_sub((g3s_vector *)ep, (g3s_vector *)prev, (g3s_vector *)vert);
928 g3_vec_sub((g3s_vector *)en, (g3s_vector *)next, (g3s_vector *)vert);
929 g3_vec_sub((g3s_vector *)tp, (g3s_vector *)p, (g3s_vector *)vert);
930 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("vert: (%d) %q %q %q\n", best_vert, PTARGS(vert)));
931 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("prev: (%d) %q %q %q\n", pr, PTARGS(prev)));
932 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("next: (%d) %q %q %q\n", nx, PTARGS(next)));
933 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Normal code is %d\n", normcode));
934
935 // now throw out one of the coordinates
936 i1 = normcode_indices[normcode][0];
937 i2 = normcode_indices[normcode][1];
938
939 a1 = edgep[i1];
940 a2 = edgep[i2];
941 b1 = edgen[i1];
942 b2 = edgen[i2];
943 p1 = topt[i1];
944 p2 = topt[i2];
945 // now that we've picked the coordinate system, transform the point into the edge basis.
946 c1 = fix_mul(b2, p1) - fix_mul(b1, p2);
947 c2 = fix_mul(a1, p2) - fix_mul(a2, p1);
948 d = fix_mul(a1, b2) - fix_mul(a2, b1);
949 if (d < 0)
950 c1 = -c1, c2 = -c2, d = -d;
951 PHYS_SPEW(DSRC_PHYSICS_Terrain,
952 ("a: %q %q, b %q %q, c %q %q, p %q %q d %q\n", fix_float(a1), fix_float(a2), fix_float(b1),
953 fix_float(b2), fix_float(c1), fix_float(c2), fix_float(p1), fix_float(p2), fix_float(d)));
954 if (c1 < 0 || c2 < 0) {
955 fix mag;
956 // we're outside the quadrilateral
957 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Outside the quad\n"));
958 if (c1 > 0) {
959 p1 -= fix_mul(c1, a1);
960 p2 -= fix_mul(c1, a2);
961 } else if (c2 > 0) {
962 p1 -= fix_mul(c2, b1);
963 p2 -= fix_mul(c2, b2);
964 } else {
965 mag = g3_vec_mag((g3s_vector *)topt);
966 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q mag %q\n", PTARGS(topt), fix_float(mag)));
967 return mag;
968 }
969 topt[i1] = p1;
970 topt[i2] = p2;
971
972 mag = g3_vec_mag((g3s_vector *)topt);
973 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q mag %q\n", PTARGS(topt), fix_float(mag)));
974 return mag;
975 } else
976 return 0;
977 }
978 }
979
980 #define mod3(x) (((x) > 2) ? (x)-3 : (x))
981
facelet_distance_sq_3points(pt3d pt,pt3d flet[NUM_POINTS],uchar normcode)982 fix facelet_distance_sq_3points(pt3d pt, pt3d flet[NUM_POINTS], uchar normcode) {
983 int i;
984 fix best_dsq = FIX_MAX; // minimum distance squared
985 int best_vert = -1;
986 fix *best_edge;
987 fix *cprod_edge;
988 fix cprod_msq;
989 pt3d edgen;
990 pt3d cprod;
991 pt3d edgep;
992 pt3d topt; // vertex to point;
993 for (i = 0; i < 3; i++) {
994 int next = mod3(i + 1);
995 pt3d edge; // edge vector
996 // build the edge & point vectors
997 {
998 // fix* e = edge;
999 // fix* n = flet[next];
1000 fix *t = topt;
1001 fix *p = pt;
1002 fix *v = flet[i];
1003 // *(e++) = *(n++) - *(v);
1004 *(t++) = *(p++) - *(v++);
1005 // *(e++) = *(n++) - *(v);
1006 *(t++) = *(p++) - *(v++);
1007 // *(e++) = *(n++) - *(v);
1008 *(t++) = *(p++) - *(v++);
1009 }
1010 {
1011 fix result;
1012 dotprod(topt, topt, result);
1013 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q dsq %d best_dsq %d\n", PTARGS(topt), result, best_dsq));
1014 if (result < best_dsq) {
1015 best_dsq = result;
1016 best_vert = i;
1017 }
1018 }
1019 }
1020 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Closest vertex %d\n", best_vert));
1021 {
1022 fix a1, a2, b1, b2, p1, p2, c1, c2;
1023 fix d;
1024 int nx = (best_vert < 2) ? best_vert + 1 : 0;
1025 int pr = (best_vert > 0) ? best_vert - 1 : 2;
1026 fix *ep = edgep;
1027 fix *en = edgen;
1028 fix *tp = topt;
1029 fix *p = pt;
1030 fix dp;
1031 fix cp, cn;
1032 fix dn;
1033 fix msp;
1034 fix msn;
1035 fix *vert = &flet[best_vert][0];
1036 fix *prev = &flet[pr][0];
1037 fix *next = &flet[nx][0];
1038 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("vert: (%d) %q %q %q\n", best_vert, PTARGS(vert)));
1039 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("prev: (%d) %q %q %q\n", pr, PTARGS(prev)));
1040 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("next: (%d) %q %q %q\n", nx, PTARGS(next)));
1041 *(ep++) = *(prev++) - *(vert);
1042 *(en++) = *(next++) - *(vert);
1043 *(tp++) = *(p++) - *(vert);
1044 vert++;
1045 *(ep++) = *(prev++) - *(vert);
1046 *(en++) = *(next++) - *(vert);
1047 *(tp++) = *(p++) - *(vert);
1048 vert++;
1049 *(ep++) = *(prev++) - *(vert);
1050 *(en++) = *(next++) - *(vert);
1051 *(tp++) = *(p++) - *(vert);
1052 vert++;
1053 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Normal code is %d\n", normcode));
1054
1055 // now throw out one of the coordinates
1056 switch (normcode) {
1057 case NORMAL_X:
1058 a1 = edgep[1];
1059 a2 = edgep[2];
1060 b1 = edgen[1];
1061 b2 = edgen[2];
1062 p1 = topt[1];
1063 p2 = topt[2];
1064 break;
1065 case NORMAL_Y:
1066 a1 = edgep[0];
1067 a2 = edgep[2];
1068 b1 = edgen[0];
1069 b2 = edgen[2];
1070 p1 = topt[0];
1071 p2 = topt[2];
1072 break;
1073 case NORMAL_Z:
1074 a1 = edgep[0];
1075 a2 = edgep[1];
1076 b1 = edgen[0];
1077 b2 = edgen[1];
1078 p1 = topt[0];
1079 p2 = topt[1];
1080 break;
1081 }
1082 // now that we've picked the coordinate system, transform the point into the edge basis.
1083 c1 = fix_mul(b2, p1) - fix_mul(b1, p2);
1084 c2 = -fix_mul(a2, p1) + fix_mul(a1, p2);
1085 d = fix_mul(a1, b2) - fix_mul(a2, b1);
1086 if (d < 0)
1087 c1 = -c1, c2 = -c2, d = -d;
1088 PHYS_SPEW(DSRC_PHYSICS_Terrain,
1089 ("a: %q %q, b %q %q, c %q %q, p %q %q d %q\n", fix_float(a1), fix_float(a2), fix_float(b1),
1090 fix_float(b2), fix_float(c1), fix_float(c2), fix_float(p1), fix_float(p2), fix_float(d)));
1091 if (c1 < 0 || c2 < 0) {
1092 fix mag;
1093 // we're outside the quadrilateral
1094 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Outside the quad\n"));
1095 if (c1 > 0) {
1096 p1 -= fix_mul(c1, a1);
1097 p2 -= fix_mul(c1, a2);
1098 } else if (c2 > 0) {
1099 p1 -= fix_mul(c2, b1);
1100 p2 -= fix_mul(c2, b2);
1101 } else {
1102 mag = g3_vec_mag((g3s_vector *)topt);
1103 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q mag %q\n", PTARGS(topt), fix_float(mag)));
1104 return mag;
1105 }
1106 switch (normcode) {
1107 case NORMAL_X:
1108 topt[1] = p1;
1109 topt[2] = p2;
1110 break;
1111 case NORMAL_Y:
1112 topt[0] = p1;
1113 topt[2] = p2;
1114 break;
1115 case NORMAL_Z:
1116 topt[0] = p1;
1117 topt[1] = p2;
1118 break;
1119 }
1120
1121 mag = g3_vec_mag((g3s_vector *)topt);
1122 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("topt %q %q %q mag %q\n", PTARGS(topt), fix_float(mag)));
1123 return mag;
1124 } else
1125 return 0;
1126 }
1127 }
1128
1129 // Given a facelet, translate it r units in the direction of its normal.
1130 // (Mutates the facelet in place, leaves the normal intact)
1131
grow_facelet(fix r,fix flet[NUM_POINTS][3])1132 void grow_facelet(fix r, fix flet[NUM_POINTS][3]) {
1133 pt3d *coor = flet;
1134 g3s_vector norm;
1135 fix *realnorm = flet[NORM_IDX];
1136
1137 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Growing by %q\n", fix_float(r)));
1138 // scale the normal vector
1139 g3_vec_scale(&norm, (g3s_vector *)realnorm, r);
1140 // now translate the coords three times
1141 g3_vec_add((g3s_vector *)*coor, (g3s_vector *)*coor, &norm);
1142 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Point 0: %q %q %q\n", PTARGS(*coor)));
1143 coor++;
1144 g3_vec_add((g3s_vector *)*coor, (g3s_vector *)*coor, &norm);
1145 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Point 1: %q %q %q\n", PTARGS(*coor)));
1146 coor++;
1147 g3_vec_add((g3s_vector *)*coor, (g3s_vector *)*coor, &norm);
1148 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Point 2: %q %q %q\n", PTARGS(*coor)));
1149 coor++;
1150 if (**coor != NO_POINT) // is there a fourth point?
1151 {
1152 g3_vec_add((g3s_vector *)*coor, (g3s_vector *)*coor, &norm);
1153 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("Point 3: %q %q %q\n", PTARGS(*coor)));
1154 }
1155 }
1156 #else
1157 typedef fix pt3d[3];
1158 #endif
1159
1160 #pragma disable_message(202)
FF_terrain(fix X,fix Y,fix Z,uchar fast,void * TFF)1161 uchar FF_terrain(fix X, fix Y, fix Z, uchar fast, void *TFF) { return (TRUE); }
FF_raycast(fix x,fix y,fix z,fix vec[3],fix range,fix where_hit[3],terrain_ff * tff)1162 uchar FF_raycast(fix x, fix y, fix z, fix vec[3], fix range, fix where_hit[3], terrain_ff *tff) { return (TRUE); }
1163 #pragma disable_message(202)
1164
1165 // ?????
Terrain(fix fix_x,fix fix_y,fix fix_z,fix rad)1166 void Terrain(fix fix_x, fix fix_y, fix fix_z, fix rad) {}
1167
1168 #ifdef OLD_TERR_FUNC
1169 extern fix tfunc_rad, tfunc_pt[3];
1170 extern fix tfunc_sum[3];
1171 extern int tfunc_cnt[3];
1172 extern fix tfunc_norms[3][3]; // floor, wall, ceil
1173
full_3d_facelet_action(fix (* fleto)[3],int which)1174 void full_3d_facelet_action(fix (*fleto)[3], int which) // fix (*norm)[3], int *cnt, fix *sum)
1175 {
1176 fix proj;
1177 pt3d projpt;
1178 fix dist;
1179 pt3d *flet = fleto;
1180
1181 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("full 3d %d\n", which))
1182 grow_facelet(tfunc_rad, flet);
1183 proj = project_onto_facelet(tfunc_pt, projpt, flet);
1184 // proj must be between 0 and -rad
1185 if (proj > 0 || proj < -tfunc_rad)
1186 return;
1187 if (flet[3][0] == NO_POINT)
1188 dist = facelet_distance_sq_3points(projpt, flet, compute_normal_code(flet[NORM_IDX]));
1189 else
1190 dist = facelet_distance_sq_4points(projpt, flet, compute_normal_code(flet[NORM_IDX]));
1191
1192 // PHYS_SPEW(DSRC_PHYSICS_Terrain,("Distance from facelet %d is %q, proj %q
1193 // \n",i,fix_float(dist),fix_float(proj)));
1194 // if we're closer than our radius,
1195 // scale and add to wall gradient.
1196 if (-proj <= tfunc_rad - dist) {
1197 tfunc_cnt[which]++;
1198 g3_vec_add((g3s_vector *)tfunc_norms[which], (g3s_vector *)tfunc_norms[which], (g3s_vector *)flet[NORM_IDX]);
1199 tfunc_sum[which] -= proj;
1200 PHYS_SPEW(DSRC_PHYSICS_Terrain, ("sum %q, which %d\n", fix_float(-proj), which));
1201 }
1202 }
1203 #endif
1204
1205 ubyte param_matters[MAP_TYPES] = {
1206 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1207 };
1208 #endif // NOT_YET
1209
physics_init()1210 errtype physics_init() {
1211 EDMS_data init_data;
1212
1213 // Start EDMS
1214 init_data.playfield_size = fix_make(MAP_XSIZE + 4, 0); // note assumption that X and Y sizes are same
1215 init_data.min_physics_handle = 0;
1216 init_data.collision_callback = cit_collision_callback;
1217 init_data.snooz_callback = cit_sleeper_callback;
1218 init_data.autodestruct_callback = cit_autodestruct_callback;
1219 init_data.awol_callback = cit_awol_callback;
1220 init_data.argblock_pointer = (void *)big_buffer;
1221 EDMS_startup(&init_data);
1222
1223 // Create some defaults
1224 LG_memset(&standard_state, 0, sizeof(State)); // _memset32l(&standard_state,0,12);
1225
1226 return (OK);
1227 }
1228
1229 #define NUM_WARMUP_ITERATIONS 10
1230 #define EDMS_WARMUP_TIMESTEP fix_make(0, 0x2000)
1231
1232 /* KLC - doesn't do anything.
1233 errtype physics_warmup()
1234 {
1235 // int i;
1236 // for (i=0; i < NUM_WARMUP_ITERATIONS; i++)
1237 // EDMS_soliton_vector(EDMS_WARMUP_TIMESTEP);
1238 return(OK);
1239 }
1240 */
1241
apply_gravity_to_one_object(ObjID oid,fix new_grav)1242 errtype apply_gravity_to_one_object(ObjID oid, fix new_grav) {
1243 errtype err = OK;
1244 if (CHECK_OBJ_PH(oid)) {
1245 switch (ObjProps[OPNUM(oid)].physics_model) {
1246 case EDMS_ROBOT: {
1247 Robot parms;
1248 EDMS_get_robot_parameters(objs[oid].info.ph, &parms);
1249 parms.gravity = new_grav;
1250 EDMS_set_robot_parameters(objs[oid].info.ph, &parms);
1251 break;
1252 }
1253 case EDMS_PELVIS: {
1254 Pelvis parms;
1255 EDMS_get_pelvis_parameters(objs[oid].info.ph, &parms);
1256 parms.gravity = new_grav;
1257 EDMS_set_pelvis_parameters(objs[oid].info.ph, &parms);
1258 break;
1259 }
1260 case EDMS_DIRAC: {
1261 Dirac_frame parms;
1262 EDMS_get_Dirac_frame_parameters(objs[oid].info.ph, &parms);
1263 parms.gravity = new_grav;
1264 EDMS_set_Dirac_frame_parameters(objs[oid].info.ph, &parms);
1265 break;
1266 }
1267 default:
1268 err = ERR_RANGE;
1269 break;
1270 }
1271 }
1272 return err;
1273 }
1274
1275 // ----------------------------------------------------------------
1276 // Yucky coordinate transformation code.
1277
1278 #define SIN(x) fix_sin(x)
1279 #define COS(x) fix_cos(x)
1280
1281 // NOTE, the first index of the matrix is the ROW
1282
1283 // ----------------------------------------------
1284 // AND NOW, THE THROWING CODE
1285
1286 #define THROW_YANG_MAX FIXANG_PI / 6
1287 #define THROW_XANG_MAX FIXANG_PI / 4
1288
ID2radius(ObjID id)1289 fix ID2radius(ObjID id) {
1290 int rad = ObjProps[OPNUM(id)].physics_xr;
1291 if (rad > 0)
1292 return fix_make(rad, 0) / PHYSICS_RADIUS_UNIT;
1293 else
1294 return standard_robot.size;
1295 }
1296
1297 #define THROW_DISPLACE_RANGE (FIX_UNIT / 2)
1298 #define THROW_ORDER2_SCALE (FIX_UNIT * 2 / 3)
1299 #define THROW_RAYCAST_MASS fix_make(0, 0x2000)
1300 #define THROW_RAYCAST_SPEED fix_make(1, 0)
1301
player_throw_object(ObjID proj_id,int x,int y,int lastx,int lasty,fix vel)1302 uchar player_throw_object(ObjID proj_id, int x, int y, int lastx, int lasty, fix vel) {
1303 LGPoint pos = MakePoint(x, y);
1304 LGPoint lastpos = MakePoint(lastx, lasty);
1305 ObjLoc loc;
1306 Combat_Pt posvec;
1307 Combat_Pt vector;
1308 Combat_Pt vector2;
1309 Combat_Pt locvec;
1310 fix scale_mag;
1311 State new_state;
1312 fix radius = ID2radius(proj_id);
1313
1314 find_fire_vector(&pos, &vector);
1315 g3_vec_scale((g3s_vector *)&posvec, (g3s_vector *)&vector, THROW_DISPLACE_RANGE + radius);
1316 posvec.z += radius; // put the bottom of the object at the cursor, not the center.
1317 g3_vec_normalize((g3s_vector *)&posvec);
1318 if (CHECK_OBJ_PH(PLAYER_OBJ)) {
1319 if (global_fullmap->cyber)
1320 EDMS_get_Dirac_frame_viewpoint(objs[PLAYER_OBJ].info.ph, &new_state);
1321 else
1322 EDMS_get_pelvic_viewpoint(objs[PLAYER_OBJ].info.ph, &new_state);
1323 }
1324
1325 // loc = objs[PLAYER_OBJ].loc;
1326 locvec.x = new_state.X;
1327 locvec.y = new_state.Y;
1328 locvec.z = new_state.Z;
1329 vector2 = locvec;
1330
1331 // raycast out from the player to find a good place to put the object
1332 ray_cast_vector(PLAYER_OBJ, &locvec, posvec, THROW_RAYCAST_MASS, radius, THROW_RAYCAST_SPEED,
1333 THROW_DISPLACE_RANGE + radius);
1334
1335 g3_vec_sub((g3s_vector *)&vector2, (g3s_vector *)&locvec, (g3s_vector *)&vector2);
1336 scale_mag = g3_vec_mag((g3s_vector *)&vector2);
1337 loc.p = loc.h = loc.b = 0;
1338
1339 if (scale_mag < THROW_DISPLACE_RANGE + radius) {
1340 g3_vec_scale((g3s_vector *)&locvec, (g3s_vector *)&vector, lg_max(0, scale_mag - radius / 2));
1341 loc.x = obj_coord_from_fix(new_state.X + locvec.x);
1342 loc.y = obj_coord_from_fix(new_state.Y + locvec.y);
1343 loc.z = obj_height_from_fix(new_state.Z + locvec.z + radius);
1344 scale_mag = 0;
1345 } else {
1346 g3_vec_scale((g3s_vector *)&locvec, (g3s_vector *)&vector, lg_max(0, THROW_DISPLACE_RANGE));
1347 loc.x = obj_coord_from_fix(new_state.X + locvec.x);
1348 loc.y = obj_coord_from_fix(new_state.Y + locvec.y);
1349 loc.z = obj_height_from_fix(new_state.Z + locvec.z + radius);
1350 scale_mag = FIX_UNIT;
1351 }
1352 if (scale_mag == 0 || vel == 0)
1353 string_message_info(REF_STR_DropMessage);
1354
1355 find_fire_vector(&lastpos, &vector2);
1356 g3_vec_scale((g3s_vector *)&vector2, (g3s_vector *)&vector2, THROW_ORDER2_SCALE);
1357 g3_vec_sub((g3s_vector *)&vector, (g3s_vector *)&vector, (g3s_vector *)&vector2);
1358 g3_vec_normalize((g3s_vector *)&vector);
1359 g3_vec_scale((g3s_vector *)&vector, (g3s_vector *)&vector, fix_mul(vel, scale_mag));
1360
1361 obj_move_to_vel(proj_id, &loc, TRUE, vector.x, vector.y, vector.z);
1362 // let's ignore the thrown object
1363 EDMS_ignore_collisions(objs[PLAYER_OBJ].info.ph, objs[proj_id].info.ph);
1364 if (objs[proj_id].obclass == CLASS_GRENADE) {
1365 extern void reactivate_mine(ObjID id);
1366
1367 // let's get it to hit player after a little time
1368 if (objs[proj_id].subclass == GRENADE_SUBCLASS_DIRECT)
1369 // if (GrenadeProps[CPNUM(proj_id)].flags & GREN_MINE_TYPE)
1370 reactivate_mine(proj_id);
1371 }
1372 chg_set_flg(INVENTORY_UPDATE);
1373 return TRUE;
1374 }
1375
get_phys_info(int ph,fix * list,int cnt)1376 uchar get_phys_info(int ph, fix *list, int cnt) {
1377 ObjID id = physics_handle_id[ph];
1378 State new_state;
1379 if (ph == -1)
1380 return FALSE;
1381 get_phys_state(ph, &new_state, id);
1382 if (ObjProps[OPNUM(id)].physics_model == EDMS_ROBOT) {
1383 if (cnt > 4)
1384 cnt = 4;
1385 }
1386
1387 switch (cnt - 1) {
1388 default:
1389 if (cnt <= 0)
1390 return FALSE;
1391 case 5:
1392 list[5] = fixrad_to_fixang(new_state.gamma);
1393 case 4:
1394 list[4] = fixrad_to_fixang(-new_state.beta);
1395 case 3:
1396 list[3] = fixang_from_phys_angle(new_state.alpha);
1397 case 2:
1398 list[2] = new_state.Z;
1399 case 1:
1400 list[1] = new_state.Y;
1401 case 0:
1402 list[0] = new_state.X;
1403 }
1404 return TRUE;
1405 }
1406
1407 //-------------------------------------------
1408 // POSTURE STUFF
1409
player_set_posture(ubyte new_posture)1410 errtype player_set_posture(ubyte new_posture) {
1411 player_struct.posture = new_posture;
1412 return OK;
1413 }
1414
1415 // --------------------------------------------
1416 // LEANING
1417
player_set_lean(byte x,byte y)1418 errtype player_set_lean(byte x, byte y) {
1419 player_struct.leanx = x;
1420 player_struct.leany = y;
1421 return OK;
1422 }
1423
1424 #define FIRST_ENRG_PROJ_TYPE 7
1425
1426 // -----------------------------------------------
1427 // here is our wacky collision callback...
1428
1429 #define ENERGY_MINE_DRAIN 10
1430
1431 short PULSER_DAMAGE[10] = {10, 15, 25, 40, 60, 85, 125, 170, 260, 500};
1432
1433 #define NUM_DRILL_LEVELS 5
1434 #define MAX_DRILL_DAMAGE 725
1435 #define DRILL_DAMAGE(lev) (MAX_DRILL_DAMAGE / (NUM_DRILL_LEVELS - (lev)))
1436
1437 ubyte ice_offense_values[] = {1, 2, 3, 4};
1438 ubyte ice_penetration[] = {5, 5, 10, 15};
1439 ubyte ice_damage_modifiers[] = {10, 20, 40, 80};
1440
collide_objects(ObjID collision,ObjID victim,int bad)1441 errtype collide_objects(ObjID collision, ObjID victim, int bad) {
1442 uchar destroy_me = TRUE;
1443
1444 if (objs[collision].obclass == CLASS_GRENADE) {
1445 grenade_contact(collision, bad);
1446 } else if ((objs[collision].obclass == CLASS_PHYSICS) && (objs[collision].subclass == PHYSICS_SUBCLASS_SLOW)) {
1447 ObjID owner = objPhysicss[objs[collision].specID].owner;
1448 int a = objPhysicss[objs[collision].specID].bullet_triple;
1449 int cp_num;
1450 ObjLoc loc = objs[collision].loc;
1451 extern ObjID damage_sound_id;
1452 extern char damage_sound_fx;
1453 uchar special_proj = FALSE;
1454
1455 // set that we've already collided this time
1456 if (objPhysicss[objs[collision].specID].p3.y)
1457 return OK;
1458 else
1459 objPhysicss[objs[collision].specID].p3.y = 3;
1460
1461 if (owner != PLAYER_OBJ) {
1462 cp_num = CPNUM(owner);
1463 switch (objs[owner].obclass) {
1464 case CLASS_CRITTER:
1465 attack_object(victim, CritterProps[cp_num].attacks[a].damage_type,
1466 CritterProps[cp_num].attacks[a].damage_modifier,
1467 CritterProps[cp_num].attacks[a].offense_value,
1468 CritterProps[cp_num].attacks[a].penetration, 0, 100, NULL, 0, 0, NULL);
1469 break;
1470 default:
1471 if (global_fullmap->cyber && ICE_ICE_BABY(owner)) {
1472 attack_object(victim, CYBER_PROJECTILE_TYPE, ice_damage_modifiers[a], ice_offense_values[a],
1473 ice_penetration[a], 0, 100, NULL, 0, 0, NULL);
1474 }
1475 break;
1476 }
1477 } else {
1478 extern void slow_proj_hit(ObjID id, ObjID victim);
1479
1480 // Was the player firing a special projectile?
1481 switch (ID2TRIP(collision)) {
1482 case DRILLSLOW_TRIPLE:
1483 if (ICE_ICE_BABY(victim)) {
1484 char soft_lvl = objPhysicss[objs[collision].specID].bullet_triple;
1485 short dmg;
1486
1487 // Damage the ice -- higher level ICEs are tough, but we always
1488 // do at least a little tiny bit of damage
1489 dmg = lg_max(1, DRILL_DAMAGE(soft_lvl - 1) >> (ICE_LEVEL(victim)) * 2);
1490
1491 if (dmg < objs[victim].info.current_hp) {
1492 // If it is still alive, agitate it
1493 objs[victim].info.current_hp -= dmg;
1494 SET_ICE_AGIT(victim, lg_min(ICE_AGIT(victim) + soft_lvl, MAX_AGIT));
1495 } else {
1496 objs[victim].info.current_hp = 0;
1497 DEICE(victim);
1498 }
1499 }
1500 special_proj = TRUE;
1501 break;
1502 case CYBERSLOW_TRIPLE:
1503 if (!(ICE_ICE_BABY(victim))) {
1504 char soft_lvl = objPhysicss[objs[collision].specID].bullet_triple;
1505 simple_damage_object(victim, PULSER_DAMAGE[soft_lvl - 1], CYBER_PROJECTILE_TYPE, 0);
1506 special_proj = TRUE;
1507 }
1508 break;
1509 #ifdef MANY_CYBERSPACE_WEAPONS
1510 case DISCSLOW_TRIPLE: {
1511 char soft_lvl = objPhysicss[objs[collision].specID].bullet_triple;
1512 simple_damage_object(victim, disc_damage[soft_lvl - 1], CYBER_PROJECTILE_TYPE, 0);
1513 special_proj = TRUE;
1514 } break;
1515 case SPEWSLOW_TRIPLE: {
1516 char soft_lvl = objPhysicss[objs[collision].specID].bullet_triple;
1517 simple_damage_object(victim, cyberspew_damage[soft_lvl - 1], CYBER_PROJECTILE_TYPE, 0);
1518 special_proj = TRUE;
1519 }
1520 #else
1521 case SPEWSLOW_TRIPLE:
1522 case DISCSLOW_TRIPLE:
1523 special_proj = TRUE;
1524 break;
1525 #endif
1526 break;
1527 }
1528
1529 if (!special_proj)
1530 slow_proj_hit(collision, victim);
1531 }
1532
1533 // Why are we destroying "victim" if it's a slow projectile?!?!
1534 // cause the other one can't damage this one - because it'll be destroyed.
1535 // only one call allowed
1536
1537 // this big if here - says that if both objects are physics objects
1538 // do the thing the flags say! (what to destroy)
1539 if ((objs[victim].obclass == CLASS_PHYSICS) && (objs[victim].subclass == PHYSICS_SUBCLASS_SLOW)) {
1540 if (!(PhysicsProps[CPNUM(victim)].flags & PROJ_PRESERVE_PROJ_HIT))
1541 ADD_DESTROYED_OBJECT(victim);
1542
1543 if (!(PhysicsProps[CPNUM(collision)].flags & PROJ_PRESERVE_PROJ_HIT))
1544 ADD_DESTROYED_OBJECT(collision);
1545 } else if (!(PhysicsProps[CPNUM(collision)].flags & PROJ_PRESERVE_HIT))
1546 ADD_DESTROYED_OBJECT(collision);
1547
1548 if (damage_sound_fx != -1) {
1549 play_digi_fx_obj(damage_sound_fx, 1, damage_sound_id);
1550 }
1551 damage_sound_fx = -1;
1552 } else if ((ID2TRIP(collision) == ENERGY_MINE_TRIPLE) && (victim == PLAYER_OBJ)) {
1553 player_struct.energy = lg_max(0, player_struct.energy - ENERGY_MINE_DRAIN);
1554 if (!digi_fx_playing(SFX_ENERGY_DRAIN, NULL))
1555 play_digi_fx(SFX_ENERGY_DRAIN, 1);
1556 chg_set_flg(VITALS_UPDATE);
1557 }
1558 return (OK);
1559 }
1560
terrain_object_collide(physics_handle src,ObjID target)1561 void terrain_object_collide(physics_handle src, ObjID target) {
1562 ObjID hit_obj = physics_handle_to_id(src);
1563 if (is_obj_destroyed(hit_obj) || is_obj_destroyed(target))
1564 return;
1565 collide_objects(target, hit_obj, 0);
1566 }
1567
cit_collision_callback(physics_handle C,physics_handle V,int32_t bad,int32_t DATA1,int32_t DATA2,fix location[3])1568 void cit_collision_callback(physics_handle C, physics_handle V, int32_t bad, int32_t DATA1, int32_t DATA2, fix location[3]) {
1569 ObjID collision;
1570 ObjID victim;
1571
1572 collision = physics_handle_to_id(C);
1573 if (is_obj_destroyed(collision))
1574 return;
1575 victim = physics_handle_to_id(V);
1576 if (is_obj_destroyed(victim))
1577 return;
1578 collide_objects(collision, victim, bad);
1579 }
1580
cit_awol_callback(physics_handle caller)1581 void cit_awol_callback(physics_handle caller) {
1582 State s;
1583
1584 if (caller != -1)
1585 get_phys_state(caller, &s, OBJ_NULL);
1586 else {
1587 return;
1588 }
1589 if ((fix_int(s.X) > global_fullmap->x_size) || (s.X < 0) || (fix_int(s.Y) > global_fullmap->y_size) || (s.Y < 0)) {
1590 if (caller != -1) {
1591 ADD_DESTROYED_OBJECT(physics_handle_to_id(caller));
1592 }
1593 }
1594 }
1595
cit_sleeper_callback(physics_handle caller)1596 void cit_sleeper_callback(physics_handle caller) {
1597 ObjID id;
1598 id = physics_handle_to_id(caller);
1599
1600 // Is this a kind of thing that wants to maintain it's physics-ness?
1601 // Live grenades should do this...
1602 if (ObjProps[OPNUM(id)].flags & EDMS_PRESERVE) {
1603 // Do put-to-sleep code here.
1604 } else {
1605 if (ID2TRIP(id) == L_MINE_TRIPLE) {
1606 if (objGrenades[objs[id].specID].flags & GREN_ACTIVE_FLAG) {
1607 objGrenades[objs[id].specID].flags |= GREN_MINE_STILL;
1608 EDMS_obey_collisions(caller);
1609 return; // let's not put it to sleep
1610 }
1611 }
1612 add_edms_delete(caller);
1613 }
1614 }
1615
cit_autodestruct_callback(physics_handle h)1616 void cit_autodestruct_callback(physics_handle h) {}
1617
1618 uchar robot_antisocial = FALSE;
1619
1620 // Build the model given a state and object ID, and assign appropriate
1621 // data into the object and do appropriate bookkeeping
assemble_physics_object(ObjID id,State * pnew_state)1622 errtype assemble_physics_object(ObjID id, State *pnew_state) {
1623 switch (ObjProps[OPNUM(id)].physics_model) {
1624 case EDMS_ROBOT: {
1625 Obj *pObj = &objs[id];
1626
1627 Robot new_robot;
1628 instantiate_robot(ID2TRIP(id), &new_robot);
1629 pObj->info.ph = EDMS_make_robot(&new_robot, pnew_state);
1630 if (CHECK_OBJ_PH(id)) {
1631 if (robot_antisocial)
1632 EDMS_make_robot_antisocial(pObj->info.ph);
1633
1634 #ifdef SECRET_NON_COLLISION_BITS
1635 if ((global_fullmap->cyber) && (pObj->obclass == CLASS_PHYSICS) &&
1636 (pObj->subclass == PHYSICS_SUBCLASS_SLOW))
1637 set_secret_non_collision_bit(pObj->info.ph);
1638 #endif
1639 physics_handle_id[pObj->info.ph] = id;
1640 }
1641 break;
1642 }
1643
1644 case EDMS_PELVIS: {
1645 Pelvis new_pelvis;
1646 instantiate_pelvis(ID2TRIP(id), &new_pelvis);
1647 objs[id].info.ph = EDMS_make_pelvis(&new_pelvis, pnew_state);
1648 physics_handle_id[objs[id].info.ph] = id;
1649 break;
1650 }
1651 case EDMS_DIRAC: {
1652 Dirac_frame new_dirac;
1653 instantiate_dirac(ID2TRIP(id), &new_dirac);
1654 objs[id].info.ph = EDMS_make_Dirac_frame(&new_dirac, pnew_state);
1655 physics_handle_id[objs[id].info.ph] = id;
1656 break;
1657 }
1658 }
1659 if ((CHECK_OBJ_PH(id)) && (objs[id].info.ph > physics_handle_max))
1660 physics_handle_max = objs[id].info.ph;
1661 return (OK);
1662 }
1663
1664 // ======================================================================
1665 // MODEL STUFF
1666
1667 // -------------------------------------------
1668 // instantiate_robot() fills in the fields of a robot
1669 // structure from object properties specified by triple,
1670 // and level properties.
1671
instantiate_robot(int triple,Robot * new_robot)1672 void instantiate_robot(int triple, Robot *new_robot) {
1673 int newmass, newsize;
1674 short hard, pep;
1675
1676 *new_robot = standard_robot;
1677 switch (level_gamedata.gravity) {
1678 case LEVEL_GRAV_LOW:
1679 new_robot->gravity = fix_div(standard_robot.gravity, fix_make(3, 0));
1680 break;
1681 case LEVEL_GRAV_ZERO:
1682 new_robot->gravity = 0;
1683 break;
1684 default:
1685 if (global_fullmap->cyber ||
1686 (((TRIP2CL(triple) == CLASS_CRITTER) && (CritterProps[CPTRIP(triple)].flags & AI_FLAG_FLYING)) ||
1687 (triple == ENERGY_MINE_TRIPLE)))
1688 new_robot->gravity = 0;
1689 break;
1690 }
1691 newmass = ObjProps[OPTRIP(triple)].mass;
1692 if (newmass > 0)
1693 new_robot->mass = fix_make(newmass, 0) / (PHYS_MASS_UNIT * PHYS_MASS_C_NUM / PHYS_MASS_C_DEN);
1694 newsize = ObjProps[OPTRIP(triple)].physics_xr;
1695 if (newsize > 0)
1696 new_robot->size = fix_make(newsize, 0) / PHYSICS_RADIUS_UNIT;
1697 hard = ObjProps[OPTRIP(triple)].hardness;
1698 if (hard > 0)
1699 new_robot->hardness = fix_make(hard, 0) / PHYS_HARDNESS_UNIT;
1700 pep = ObjProps[OPTRIP(triple)].pep;
1701 if (pep > 0)
1702 new_robot->pep = fix_make(pep, 0) / PHYS_PEP_UNIT;
1703 // new_robot->cyber_space = global_fullmap->cyber ? 2 : 0;
1704 if (new_robot->gravity)
1705 new_robot->cyber_space = 0;
1706 else
1707 new_robot->cyber_space = 1;
1708 }
1709
1710 // -------------------------------------------
1711 // instantiate_pelvis() fills in the fields of a pelvis
1712 // structure from object properties specified by triple,
1713 // and level properties.
1714
instantiate_pelvis(int triple,Pelvis * new_pelvis)1715 void instantiate_pelvis(int triple, Pelvis *new_pelvis) {
1716 int newmass, newsize;
1717 short hard, pep;
1718
1719 *new_pelvis = standard_pelvis;
1720 switch (level_gamedata.gravity) {
1721 case LEVEL_GRAV_LOW:
1722 new_pelvis->gravity = fix_div(standard_pelvis.gravity, fix_make(3, 0));
1723 break;
1724 case LEVEL_GRAV_ZERO:
1725 new_pelvis->gravity = 0;
1726 break;
1727 default:
1728 if (global_fullmap->cyber)
1729 new_pelvis->gravity = 0;
1730 break;
1731 }
1732
1733 newmass = ObjProps[OPTRIP(triple)].mass;
1734 if (newmass > 0)
1735 new_pelvis->mass = fix_make(newmass, 0) / (PHYS_MASS_UNIT * PHYS_MASS_C_NUM / PHYS_MASS_C_DEN);
1736 newsize = ObjProps[OPTRIP(triple)].physics_xr;
1737 if (newsize > 0)
1738 new_pelvis->size = fix_make(newsize, 0) / PHYSICS_RADIUS_UNIT;
1739 hard = ObjProps[OPTRIP(triple)].hardness;
1740 if (hard > 0)
1741 new_pelvis->hardness = fix_make(hard, 0) / PHYS_HARDNESS_UNIT;
1742 pep = ObjProps[OPTRIP(triple)].pep;
1743 if (pep > 0)
1744 new_pelvis->pep = fix_make(pep, 0) / PHYS_PEP_UNIT;
1745 if (global_fullmap->cyber)
1746 new_pelvis->cyber_space = PELVIS_MODE_CYBER;
1747 else
1748 new_pelvis->cyber_space = (motionware_mode == MOTION_SKATES) ? PELVIS_MODE_SKATES : PELVIS_MODE_NORMAL;
1749 }
1750
1751 // -------------------------------------------
1752 // instantiate_dirac() fills in the fields of a Dirac_frame
1753 // structure from object properties specified by triple,
1754 // and level properties.
1755
instantiate_dirac(int triple,Dirac_frame * new_dirac)1756 void instantiate_dirac(int triple, Dirac_frame *new_dirac) {
1757 int newmass;
1758 short hard, rough;
1759
1760 *new_dirac = standard_dirac;
1761 switch (level_gamedata.gravity) {
1762 case LEVEL_GRAV_LOW:
1763 new_dirac->gravity = fix_div(standard_dirac.gravity, fix_make(3, 0));
1764 break;
1765 case LEVEL_GRAV_ZERO:
1766 WARN("%s: Zero gravity level!", __FUNCTION__);
1767 new_dirac->gravity = 0;
1768 break;
1769 default:
1770 // if (global_fullmap->cyber)
1771 // new_dirac->gravity = 0;
1772 break;
1773 }
1774 newmass = ObjProps[OPTRIP(triple)].mass;
1775 if (newmass > 0)
1776 new_dirac->mass = fix_make(newmass, 0) / (PHYS_MASS_UNIT * PHYS_MASS_C_NUM / PHYS_MASS_C_DEN);
1777 hard = ObjProps[OPTRIP(triple)].hardness;
1778 if (hard > 0)
1779 new_dirac->hardness = fix_make(hard, 0) / PHYS_HARDNESS_UNIT;
1780 rough = ObjProps[OPTRIP(triple)].pep;
1781 if (rough > 0)
1782 new_dirac->roughness = fix_make(rough, 0) / PHYS_ROUGHNESS_UNIT;
1783
1784 // Whut the heck do we do for the corners of a Dirac_frame? Beyond my feeble ken, I fear.
1785 // DIRAC_FIX
1786 }
1787