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  * $Header: n:/project/lib/src/edms/RCS/interfac.cc 1.11 1994/04/20 18:44:15 roadkill Exp $
21  */
22 
23 //	State information and utilities...
24 //	========================
25 
26 #include "fixpp.h"
27 #include "edms_int.h"
28 #include "idof.h"
29 
30 #pragma require_prototypes off // Added by KC for this file for Mac version.
31 
32 #ifdef EDMS_SHIPPABLE
33 //#include "mout.h"
34 #endif
35 
36 //	Here we need include files for each and every model that we'll be using...
37 //	=====================================================
38 #include "robot.h"
39 
40 //	The physics handles definitions...
41 //	==================================
42 #include "physhand.h"
43 
44 //      Sanity...
45 //      ---------
46 extern int EDMS_integrating;
47 
48 //	Callbacks...
49 //	============
50 void (*EDMS_object_collision)(physics_handle caller, physics_handle victim, int32_t badness, int32_t DATA1,
51                               int32_t DATA2, fix location[3]) = NULL,
52                                   (*EDMS_autodestruct)(physics_handle caller) = NULL,
53                                   (*EDMS_off_playfield)(physics_handle caller) = NULL,
54                                   (*EDMS_sleepy_snoozy)(physics_handle caller) = NULL;
55 
56 //	Robots...
57 //	---------
58 typedef struct {
59     fix mass, size, hardness, pep, gravity;
60     int32_t cyber_space;
61 } Robot;
62 
63 //	Conversions...
64 //	==============
65 //	physics handle to object number...
66 //	----------------------------------
67 object_number ph2on[MAX_OBJ];
68 
69 //	Object number to physics handle...
70 //	----------------------------------
71 physics_handle on2ph[MAX_OBJ];
72 
73 //	Constants...
74 //	============
75 Q fix_zero = 0.;
76 
77 //	Bridge routine to the terrain functions.  C++ functions are all lower case, C are Capped...
78 //	===========================================================================================
79 
80 //	This is outside the extern "C" {} thing
81 //	because it is not called by the user,
82 //	but rather calls the user function Terrain().
83 //	=============================================
terrain(Q X,Q Y,int32_t deriv)84 Q terrain(Q X, Q Y, int32_t deriv) {
85     Q ans;
86 
87     printf("There is no terrain in space!\n");
88     // ans.fix_to( Terrain( X.to_fix(), Y.to_fix(), deriv ) );
89     return ans;
90 }
91 
92 //	Same with Indoors...
93 //	--------------------
indoor_terrain(Q X,Q Y,Q Z,Q R,physics_handle ph,TFType type)94 TerrainHit indoor_terrain(Q X, Q Y, Q Z, Q R, physics_handle ph, TFType type) {
95     if ((X > 1) && (Y > 1) && (X < 64) && (Y < 64)) {
96         return Indoor_Terrain(X.to_fix(), Y.to_fix(), Z.to_fix(), R.to_fix(), ph, type);
97     } else {
98         //      EDMS_robot_global_badness_indicator = 1000;
99         //      mout << "!EDMS: integrator = " << EDMS_integrating << " !!\n";
100         //      mout << "!EDMS: Physics handle: " << ph << " is asking for bad terrain.\n";
101         //      mout << "!EDMS: Asked for location: (" << X << ", " << Y << ", " << Z << ").\n";
102 
103         if (ph > -1) {
104             int on = ph2on[ph];
105             //         mout << "!EDMS: Integration location (should match): (" << A[on][0][0] << ", " << A[on][1][0] <<
106             //         ", " << A[on][2][0] << ").\n"; mout << "!EDMS: Object location last frame: (" << S[on][0][0] <<
107             //         ", " << S[on][1][0] << ", " << S[on][2][0] << ").\n"; mout << "!EDMS: Sleep: " <<
108             //         no_no_not_me[on] << ", EDMS_sanity_check = " << sanity_check() << ".\n"; mout << "!EDMS: object
109             //         number " << on << ", EDMS_type: " << I[on][30] << "\n"; mout << "!EDMS: Calling AWOL
110             //         callback...\n"; mout << "Awol in interfac.cc\n";
111 
112             EDMS_off_playfield(ph);
113             no_no_not_me[on] = 0; // Safety!!!
114         } else {
115             //         mout << "!EDMS: No further information is available for physics handle -1.  SORRY!\n";
116         }
117     }
118     // If we're off the map, we should probably terminate the search.
119     return HIT_FACELET;
120 }
121 
122 //      And with Freefall...
123 //      --------------------
ff_terrain(Q X,Q Y,Q Z,uchar fast,terrain_ff * FFT)124 bool ff_terrain(Q X, Q Y, Q Z, uchar fast, terrain_ff *FFT) {
125     return FF_terrain(X.to_fix(), Y.to_fix(), Z.to_fix(), fast, FFT);
126 }
127 
ff_raycast(Q x,Q y,Q z,Fixpoint * vec,Q range,Fixpoint * where_hit,terrain_ff * FFT)128 bool ff_raycast(Q x, Q y, Q z, Fixpoint *vec, Q range, Fixpoint *where_hit, terrain_ff *FFT) {
129     return FF_raycast(x.to_fix(), y.to_fix(), z.to_fix(), (fix *)vec, range.to_fix(), (fix *)where_hit, FFT);
130 }
131 
FF_terrain(fix X,fix Y,fix Z,uchar fast,terrain_ff * TFF)132 bool FF_terrain(fix X, fix Y, fix Z, uchar fast, terrain_ff *TFF) { return (true); }
133 
FF_raycast(fix x,fix y,fix z,fix * vec,fix range,fix * where_hit,terrain_ff * tff)134 bool FF_raycast(fix x, fix y, fix z, fix *vec, fix range, fix *where_hit, terrain_ff *tff) { return (true); }
135 
136 //	We need to link to c...
137 //	=======================
138 extern "C" {
139 
140 //	Startup the mighty and perilous EDMS engine...
141 //	==============================================
EDMS_startup(EDMS_data * D)142 void EDMS_startup(EDMS_data *D) {
143     //	Stoke the internals...
144     //	======================
145     EDMS_initialize(D);
146 
147     //	Get the handles in order...
148     //	===========================
149     EDMS_init_handles();
150 
151     //	Set the callbacks...
152     //	====================
153     EDMS_object_collision = D->collision_callback;
154     EDMS_autodestruct = D->autodestruct_callback;
155     EDMS_off_playfield = D->awol_callback;
156     EDMS_sleepy_snoozy = D->snooz_callback;
157 
158     //	Done.
159     //	=====
160 }
161 
162 //////////////////////////////
163 //
164 // Tells EDMS what space to use for A
165 //
EDMS_set_workspace(void * place)166 void EDMS_set_workspace(void *place) { A = (EDMS_Argblock_Pointer)place; }
167 
168 //	Although this seems a very stupid way to do this, it's actually not...
169 //	======================================================================
170 
171 //	Autodestruct gets turned on...
172 //	==============================
EDMS_set_autodestruct(physics_handle ph)173 void EDMS_set_autodestruct(physics_handle ph) {
174     if (ph > -1) {
175         int32_t object = ph2on[ph];
176         I[object][38] = 1;
177     }
178 }
179 
180 //	Autodestruct gets turned off...
181 //	===============================
EDMS_defuse_autodestruct(physics_handle ph)182 void EDMS_defuse_autodestruct(physics_handle ph) {
183     if (ph > -1) {
184         int object = ph2on[ph];
185         I[object][38] = 0;
186     }
187 }
188 
189 // I am death incarnate.  666. So there.
190 // =====================================
EDMS_kill_object(physics_handle ph)191 void EDMS_kill_object(physics_handle ph) {
192     // Are you there, really???
193     // ========================
194     if (ph > -1) {
195         int on = physics_handle_to_object_number(ph), i;
196 
197         // Do it, just do it...
198         // --------------------
199         EDMS_kill(on);
200         EDMS_release_object(ph);
201 
202         // Simulate the action of soliton packing...
203         // -----------------------------------------
204         for (i = (on + 1); (i < MAX_OBJ); i++) {
205             EDMS_remap_object_number(i, (i - 1));
206         }
207 
208         if (EDMS_integrating == 1) {
209             // mout << "Killed " << on << " while integrating!\n";
210 
211             // You were...
212             // ===========
213         }
214     }
215 }
216 
217 //	How you get your damn stuff out...
218 //	==================================
EDMS_get_state(physics_handle ph,State * s)219 void EDMS_get_state(physics_handle ph, State *s) {
220 
221     int on = physics_handle_to_object_number(ph);
222     if (on > -1 && on < MAX_OBJ) {
223         s->X = S[on][0][0].to_fix();
224         s->X_dot = S[on][0][1].to_fix();
225         s->Y = S[on][1][0].to_fix();
226         s->Y_dot = S[on][1][1].to_fix();
227         s->Z = S[on][2][0].to_fix();
228         s->Z_dot = S[on][2][1].to_fix();
229         s->alpha = S[on][3][0].to_fix();
230         s->alpha_dot = S[on][3][1].to_fix();
231         s->beta = S[on][4][0].to_fix();
232         s->beta_dot = S[on][4][1].to_fix();
233         s->gamma = S[on][5][0].to_fix();
234         s->gamma_dot = S[on][5][1].to_fix();
235     }
236 
237 #ifdef EDMS_SHIPPABLE
238     else
239         cout << "Hey, EDMS_get_state sez: physics_handle " << ph << " is nonexistant!!\n";
240 #endif
241 }
242 
243 //	This does exactly what it looks like it does.  It is up to the caller to make sure
244 //	that the transport coordinate is not dangerous, for now.  Later, perhaps,
245 //	it should make sure of this itself, since this is not a real-time kind of function...
246 //	========================================================
EDMS_holistic_teleport(physics_handle ph,State * s)247 void EDMS_holistic_teleport(physics_handle ph, State *s) {
248     if (ph > -1) {
249         int on = physics_handle_to_object_number(ph); // Who are youuuu...
250 
251         //	First, get rid of the collision hash reference (in state since frame is over)...
252         //	=====================================================
253         state_delete_object(on);
254 
255         //	Now move the thing...
256         //	=====================
257         S[on][0][0].fix_to(s->X);
258         S[on][0][1].fix_to(s->X_dot);
259         S[on][1][0].fix_to(s->Y);
260         S[on][1][1].fix_to(s->Y_dot);
261         S[on][2][0].fix_to(s->Z);
262         S[on][2][1].fix_to(s->Z_dot);
263 
264         if (I[on][30] != D_FRAME) {
265             S[on][3][0].fix_to(s->alpha);
266             S[on][3][1] = fix_zero;
267             S[on][4][0].fix_to(s->beta);
268             S[on][4][1] = fix_zero;
269             S[on][5][0].fix_to(s->gamma);
270             S[on][5][1] = fix_zero;
271         } else {
272             Q alpha, beta, gamma, sin_alpha, cos_alpha, sin_beta, cos_beta, sin_gamma, cos_gamma;
273 
274             // alpha.fix_to( s -> alpha);
275             // beta.fix_to( s -> beta);
276             // gamma.fix_to( s -> gamma);
277 
278             // For shock...
279             // ------------
280             alpha.fix_to(s->beta);
281             beta.fix_to(s->gamma);
282             gamma.fix_to(s->alpha);
283 
284             alpha = beta = 0;
285 
286             sincos(.5 * alpha, &sin_alpha, &cos_alpha);
287             sincos(.5 * beta, &sin_beta, &cos_beta);
288             sincos(.5 * gamma, &sin_gamma, &cos_gamma);
289 
290             S[on][3][0] = cos_gamma * cos_alpha * cos_beta + sin_gamma * sin_alpha * sin_beta;
291             S[on][4][0] = cos_gamma * cos_alpha * sin_beta - sin_gamma * sin_alpha * cos_beta;
292             S[on][5][0] = cos_gamma * sin_alpha * cos_beta + sin_gamma * cos_alpha * sin_beta;
293             S[on][6][0] = -cos_gamma * sin_alpha * sin_beta + sin_gamma * cos_alpha * cos_beta;
294 
295             // Derivatives
296             S[on][3][1] = 0;
297             S[on][4][1] = 0;
298             S[on][5][1] = 0;
299             S[on][6][1] = 0;
300         }
301 
302         //	Restart collisions on it...
303         //	===========================
304         state_write_object(on);
305 
306         // Gee, I hope that that is a good location, sunny, and free of solid objects...
307         // ==================================================
308     }
309 }
310 
311 //	Here we exclude objects from hitting each specific others...
312 //	============================================================
EDMS_ignore_collisions(physics_handle ph1,physics_handle ph2)313 void EDMS_ignore_collisions(physics_handle ph1, physics_handle ph2) {
314     int32_t on1, on2;
315 
316     // Safety dance...
317     // ---------------
318     if ((ph1 > -1) && (ph2 > -1)) {
319         on1 = ph2on[ph1];
320         on2 = ph2on[ph2];
321 
322         exclude_from_collisions(on1, on2);
323     }
324 }
325 
326 //	Here we reallow collisions...
327 //	=============================
EDMS_obey_collisions(physics_handle ph1)328 void EDMS_obey_collisions(physics_handle ph1) {
329     int32_t on1;
330 
331     //	Safety ballet...
332     //	---------------
333     if (ph1 > -1) {
334         on1 = ph2on[ph1];
335         reset_collisions(on1);
336     }
337 }
338 
339 //      Turns collisions OFF for a given robot, useful in a variety of household chores...
340 //      ==================================================================================
EDMS_make_robot_antisocial(physics_handle ph)341 void EDMS_make_robot_antisocial(physics_handle ph) {
342     int32_t on = 0;
343 
344     // Do you suck...
345     // --------------
346     if (ph > -1) {
347         on = ph2on[ph];
348         if (I[on][30] == ROBOT)
349             I[on][5] = -1;
350     } // You suck...
351 }
352 
353 //      Turns collisions ON for a given robot, useful in a variety of household chores...
354 //      =================================================================================
EDMS_make_robot_social(physics_handle ph)355 void EDMS_make_robot_social(physics_handle ph) {
356     int32_t on = 0;
357 
358     // Do you suck...
359     // --------------
360     if (ph > -1) {
361         on = ph2on[ph];
362         if (I[on][30] == ROBOT)
363             I[on][5] = 0;
364     } // You suck...
365 }
366 
367 // Here is a routine that will attempt to settle an object to the local b/c.  It is NOT intended for
368 // online use.  A negative return value indicates a badly placed or unphysical model...
369 // =================================================================
EDMS_settle_object(physics_handle ph)370 int32_t EDMS_settle_object(physics_handle ph) {
371     int32_t on = 0, return_value = -1;
372 
373     // Are you really there?
374     // ---------------------
375     if (ph > -1) {
376         on = ph2on[ph];
377         return_value = settle_object(on);
378     } // Happy joy...
379 
380     // All done...
381     // -----------
382     return return_value;
383 }
384 
385 //      Prints out a state vector...
386 //      ============================
EDMS_mprint_state(physics_handle ph)387 void EDMS_mprint_state(physics_handle ph) {
388     int32_t on = ph2on[ph];
389 
390     mprint_state(on);
391 }
392 
393 //	Here is the beginning of an EDMS diagnostic statistics tool...
394 //	==============================================================
EDMS_inventory_and_statistics(int32_t show_sleepers)395 void EDMS_inventory_and_statistics(int32_t show_sleepers) { inventory_and_statistics(show_sleepers); }
396 
397 //	Here is the sanity checker, but you already can read that, can't you...
398 //	=======================================================================
EDMS_sanity_check()399 int32_t EDMS_sanity_check() { return sanity_check(); }
400 
401 //	Here are the bridge routines to the "default" EDMS models, others are segregates(d)...
402 //	======================================================================================
403 
404 //	Robot routines...
405 //	==================
406 
407 //      Hardness scale for robots...
408 //      ----------------------------
409 #define ROBOT_HARD_FAC 10
410 
411 //	This guy is BROKEN FOR NOW (until we get the params finalized)...
412 //	------------------------------------------------
EDMS_get_robot_parameters(physics_handle ph,Robot * m)413 void EDMS_get_robot_parameters(physics_handle ph, Robot *m) {
414     int32_t on = physics_handle_to_object_number(ph);
415 
416 #ifdef EDMS_SHIPPABLE
417     if (I[on][IDOF_MODEL] != ROBOT)
418         mout << "You are trying to get ROBOT parameters for an " << I[on][IDOF_MODEL] << "!\n";
419 #endif
420 
421     // mout << "RD: " << I[on][IDOF_ROBOT_ROLL_DRAG] << " : M:" << I[on][IDOF_ROBOT_MASS] << "\n";
422     m->pep = (I[on][IDOF_ROBOT_ROLL_DRAG] / (1.5 * I[on][IDOF_ROBOT_MASS])).to_fix();
423     m->size = I[on][IDOF_ROBOT_RADIUS].to_fix();
424     m->hardness = (I[on][IDOF_ROBOT_K] * I[on][IDOF_ROBOT_RADIUS] / (I[on][IDOF_ROBOT_MASS] * ROBOT_HARD_FAC)).to_fix();
425     m->mass = I[on][IDOF_ROBOT_MASS].to_fix();
426     m->gravity = I[on][IDOF_ROBOT_GRAVITY].to_fix();
427     m->cyber_space = I[on][IDOF_CYBERSPACE].to_int();
428 }
429 
430 //	And the compression test for terrain "traps..."
431 //	===============================================
EDMS_get_robot_damage(physics_handle ph)432 fix EDMS_get_robot_damage(physics_handle ph) {
433     int32_t object;
434 
435     object = ph2on[ph]; // As stupid as it gets...
436     return (I[object][14]).to_fix();
437 }
438 
439 //	In flux (Thrust, attitude and JumpJets)...
440 //	==========================================
EDMS_control_robot(physics_handle ph,fix T,fix A,fix J)441 void EDMS_control_robot(physics_handle ph, fix T, fix A, fix J) {
442 
443     Q TT,   // thrust
444         AA, // attitude jets
445         JJ; // jump jets
446 
447 #ifdef EDMS_SHIPPABLE
448     if (ph < 0)
449         mout << "Hey, you are an idiot...";
450 #endif
451 
452     TT.fix_to(T);
453     AA.fix_to(A);
454     JJ.fix_to(J);
455 
456     int32_t on = physics_handle_to_object_number(ph);
457     robot_set_control(on, TT, AA, JJ);
458 }
459 
460 //	AI control routines...
461 //	======================
EDMS_ai_control_robot(physics_handle ph,fix D_H,fix D_S,fix S_S,fix U,fix * T_Y,fix D)462 void EDMS_ai_control_robot(physics_handle ph, fix D_H, fix D_S, fix S_S, fix U, fix *T_Y, fix D) {
463     Q DH,   // desired heading
464         DS, // desired speed
465         SS, // sidestep
466         UU, // urgency
467         TU, // there yet?
468         DD; // distance
469 
470 #ifdef EDMS_SHIPPABLE
471     if (ph < 0)
472         mout << "Hey, you are and idiot...";
473 #endif
474 
475     DH.fix_to(D_H);
476     DS.fix_to(D_S);
477     SS.fix_to(S_S);
478     UU.fix_to(U);
479     DD.fix_to(D);
480 
481     int32_t on = physics_handle_to_object_number(ph);
482     robot_set_ai_control(on, DH, DS, SS, UU, TU, DD);
483 
484     *T_Y = TU.to_fix();
485 }
486 
487 //	These are different parameters than for the marble now...
488 //	---------------------------------------------------------
EDMS_make_robot(Robot * m,State * s)489 physics_handle EDMS_make_robot(Robot *m, State *s) {
490     Q params[10], init_state[6][3];
491 
492     Q mass, pep, hardness, size, gravity;
493 
494     int32_t cyber_space;
495 
496     int32_t on = 0;
497     physics_handle ph = 0;
498 
499     init_state[DOF_X][0].fix_to(s->X);
500     init_state[DOF_X][1].fix_to(s->X_dot);
501     init_state[DOF_Y][0].fix_to(s->Y);
502     init_state[DOF_Y][1].fix_to(s->Y_dot);
503     init_state[DOF_Z][0].fix_to(s->Z);
504     init_state[DOF_Z][1].fix_to(s->Z_dot);
505     init_state[DOF_ALPHA][0].fix_to(s->alpha);
506     init_state[DOF_ALPHA][1].fix_to(s->alpha_dot);
507     init_state[DOF_BETA][0] = init_state[DOF_BETA][1] = init_state[DOF_GAMMA][0] = init_state[DOF_GAMMA][1] = END;
508 
509     mass.fix_to(m->mass);
510     size.fix_to(m->size);
511     // if ( size > .45/hash_scale ) size = .45/hash_scale;
512     hardness.fix_to(m->hardness);
513     pep.fix_to(m->pep);
514     gravity.fix_to(m->gravity);
515     cyber_space = m->cyber_space;
516 
517     // if (hardness > 15) { mout << "Hardness too too too: " << hardness << "\n"; hardness = 15; }
518 
519     if (mass < 1)
520         mass = 1;
521     if (mass > 30)
522         mass = 30;
523 
524     hardness = hardness * (mass * ROBOT_HARD_FAC / size);
525     if (hardness > 4000) {
526         hardness = 4000;
527         // mout << "Hard cap!\n";
528     }
529 
530     params[OFFSET(IDOF_ROBOT_K)] = hardness;
531     params[OFFSET(IDOF_ROBOT_D)] = 1.5 * sqrt(params[OFFSET(IDOF_ROBOT_K)]) * sqrt(mass);
532     params[OFFSET(IDOF_ROBOT_RADIUS)] = size;
533 
534     // mout << params[OFFSET(IDOF_ROBOT_D)] << "\n";
535 
536     params[OFFSET(IDOF_ROBOT_ROLL_DRAG)] = 1.5 * pep * mass;
537     params[OFFSET(IDOF_ROBOT_MASS_RECIP)] = 1. / mass;
538     params[OFFSET(IDOF_ROBOT_GRAVITY)] = gravity;
539     params[OFFSET(IDOF_ROBOT_MASS)] = mass;
540     // params[7] = 1. / ( .4*mass*size*size );
541     // params[8] = 5.*(1. / params[7]);
542     // params[9] = .4*mass*size*size;
543     params[OFFSET(IDOF_ROBOT_MOI)] = .4 * mass * size * size;
544     params[OFFSET(IDOF_ROBOT_ROT_DRAG)] = 5 * params[OFFSET(IDOF_ROBOT_MOI)];
545 
546     if (params[OFFSET(IDOF_ROBOT_MOI)] != 0)
547 
548         params[OFFSET(IDOF_ROBOT_MOI_RECIP)] = 1.0 / params[OFFSET(IDOF_ROBOT_MOI)];
549     else
550         params[OFFSET(IDOF_ROBOT_MOI_RECIP)] = 0.0;
551 
552     on = make_robot(init_state, params);
553 
554     // Here is where cyberspace gets turned on...
555     // ------------------------------------------
556     I[on][IDOF_CYBERSPACE] = (cyber_space > 0);
557 
558     ph = EDMS_bind_object_number(on);
559 
560 #ifdef EDMS_SHIPPABLE
561     if (params[OFFSET(IDOF_ROBOT_MOI)] == 0)
562         mout << "object " << on << " got 0 size or mass\n";
563 #endif
564 
565     return ph;
566 }
567 
EDMS_set_robot_parameters(physics_handle ph,Robot * m)568 void EDMS_set_robot_parameters(physics_handle ph, Robot *m) {
569     Q mass, hardness, size, pep, gravity;
570 
571     int32_t cyber_space;
572 
573     mass.fix_to(m->mass);
574     size.fix_to(m->size);
575     //	if ( size > .45/hash_scale ) size = .45/hash_scale;
576     hardness.fix_to(m->hardness);
577     pep.fix_to(m->pep);
578     gravity.fix_to(m->gravity);
579     cyber_space = m->cyber_space;
580 
581     int32_t on = physics_handle_to_object_number(ph);
582 
583 #ifdef EDMS_SHIPPABLE
584     if (I[on][IDOF_MODEL] != ROBOT)
585         mout << "You are trying to set ROBOT parameters for an " << I[on][30] << "!\n";
586 #endif
587 
588     //	mout << "Set Robot " << on << "\n";
589     //	mout << "	mass: " << mass << "\n";
590     //	mout << "	size: " << size << "\n";
591     //	mout << "	hard: " << hardness << "\n";
592     //	mout << "	pepp: " << pep << "\n";
593     //	mout << "	grav: " << gravity << "\n";
594 
595     if (mass < 1)
596         mass = 1;
597     if (mass > 30)
598         mass = 30;
599 
600     hardness = hardness * (mass * ROBOT_HARD_FAC / size);
601 
602     //	hardness = hardness*(mass*ROBOT_HARD_FAC/size);
603     if (hardness > 4000) {
604         hardness = 4000;
605         //                               mout << "Hard cap!\n";
606     }
607 
608     I[on][IDOF_ROBOT_K] = hardness;
609     I[on][IDOF_ROBOT_D] = 1.5 * sqrt(I[on][IDOF_ROBOT_K]) * sqrt(mass);
610     I[on][IDOF_ROBOT_RADIUS] = size;
611     I[on][IDOF_ROBOT_ROLL_DRAG] = 1.5 * pep * mass;
612     I[on][IDOF_ROBOT_MASS_RECIP] = 1. / mass;
613     I[on][IDOF_ROBOT_GRAVITY] = gravity;
614     I[on][IDOF_ROBOT_MASS] = mass;
615     I[on][IDOF_ROBOT_MOI_RECIP] = 1. / (.4 * mass * size * size);
616     I[on][IDOF_ROBOT_ROT_DRAG] = 5. * (1. / I[on][IDOF_ROBOT_MOI_RECIP]);
617     I[on][IDOF_ROBOT_MOI] = .4 * mass * size * size;
618     I[on][IDOF_CYBERSPACE] = (cyber_space > 0);
619 
620     //        mout << "Roll: " << I[on][IDOF_ROBOT_ROLL_DRAG] << "\n";
621 }
622 
623 //	Bridge routines to the solvers!!
624 //	================================
625 
626 //	4th order and very stable...
627 //	----------------------------
EDMS_soliton(fix timestep)628 void EDMS_soliton(fix timestep) {
629     Q temp;
630     temp.fix_to(timestep);
631     soliton(temp);
632 }
633 
634 //	2nd order and needs some attention...
635 //	-------------------------------------
EDMS_soliton_lite(fix timestep)636 void EDMS_soliton_lite(fix timestep) {
637     Q temp;
638     temp.fix_to(timestep);
639     soliton_lite(temp);
640 }
641 
642 //	Efficient and unstoppable...
643 //	----------------------------
EDMS_soliton_vector(fix timestep)644 void EDMS_soliton_vector(fix timestep) {
645     Q temp;
646     temp.fix_to(timestep);
647     soliton_vector(temp);
648 }
649 
650 //	Won't allow objects to collide w/one another...
651 //	-----------------------------------------------
EDMS_soliton_vector_holistic(fix timestep)652 void EDMS_soliton_vector_holistic(fix timestep) {
653     Q temp;
654     temp.fix_to(timestep);
655     soliton_vector_holistic(temp);
656 }
657 
658 //	This code here handles the mapping between the user's physics handles and the
659 //	dynamically changing intername object numbers.
660 //	==============================================
661 // 	To make a physics handle, edms calls EDMS_bind_object_number to "bind" an internal
662 // 	object number to a physics handle.  When this object number changes, the function
663 //	EDMS_remap_object_number() needs to be called to map the nu object number to
664 //	the physics number.
665 //	===================
666 // 	The physics handles are valid throughout the life of a physics object; in contrast,
667 //	the object numbers change as the array of objects is compacted.
668 //	===============================================================
669 // 	Make sure the include stuff is included before this.
670 //	====================================================
671 
672 //	Initialization... must call this, man...
673 //	========================================
EDMS_init_handles(void)674 void EDMS_init_handles(void) {
675     //	Fill with the 'end' code...
676     //	---------------------------
677     for (int32_t i = 0; i < MAX_OBJ; ++i)
678         ph2on[i] = on2ph[i] = -1;
679 }
680 
681 //	To bind a physics handle to an object number, use this function.
682 //	================================================================
EDMS_bind_object_number(object_number on)683 physics_handle EDMS_bind_object_number(object_number on) {
684     physics_handle ph = EDMS_get_free_ph();
685 
686     if (ph == -1)
687         return -1;
688 
689     ph2on[ph] = on;
690     on2ph[on] = ph;
691 
692     return ph;
693 }
694 
695 //	EDMS_remap_object_number() remaps object numbers so that the physics_handle that
696 //	used to refer to object number #old will now refer to object number #nu.
697 //	If object #old is not mapped, nothing happens...
698 //	================================================
699 
EDMS_remap_object_number(object_number old,object_number nu)700 void EDMS_remap_object_number(object_number old, object_number nu) {
701     physics_handle ph = on2ph[old];
702 
703     if (ph == -1)
704         return;
705 
706     on2ph[nu] = ph;
707     on2ph[old] = -1;
708     ph2on[ph] = nu;
709 }
710 
711 // To release the mapping between physics handle and object number
712 // (say, when deleting an object)...
713 // =================================
714 
EDMS_release_object(physics_handle ph)715 void EDMS_release_object(physics_handle ph) {
716     object_number on = ph2on[ph];
717 
718     // First, clear out the object number...
719     // -------------------------------------
720     on2ph[on] = -1;
721 
722     // Then clear out the physics_handle...
723     // ------------------------------------
724     ph2on[ph] = -1;
725 }
726 
727 // Internal routine to find an unused physics_handle.
728 // ==================================================
729 
EDMS_get_free_ph(void)730 physics_handle EDMS_get_free_ph(void) {
731     for (int32_t i = min_physics_handle; i < MAX_OBJ; ++i) {
732         // Ho, ho...
733         // ---------
734         if (ph2on[i] == -1)
735             return i;
736     }
737     // Failed to find one...
738     // ---------------------
739     return -1;
740     //	Fun...
741     //	======
742 }
743 
744 } // End of extern "C" for the &^%$@% compiler...
745