]> icculus.org git repositories - taylor/freespace2.git/blob - src/globalincs/systemvars.cpp
myrand() fixes
[taylor/freespace2.git] / src / globalincs / systemvars.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/GlobalIncs/SystemVars.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Variables and constants common to FreeSpace and Fred.
16  *
17  * $Log$
18  * Revision 1.5  2005/10/01 21:42:07  taylor
19  * if we are using a custom detail level then give the closest relative to the defaults when we request
20  *   the current detail level (needed to be fixed for one FS1 thing in particular)
21  *
22  * Revision 1.4  2003/05/25 02:30:42  taylor
23  * Freespace 1 support
24  *
25  * Revision 1.3  2002/06/09 04:41:17  relnev
26  * added copyright header
27  *
28  * Revision 1.2  2002/05/07 03:16:45  theoddone33
29  * The Great Newline Fix
30  *
31  * Revision 1.1.1.1  2002/05/03 03:28:09  root
32  * Initial import.
33  *
34  * 
35  * 12    9/09/99 8:53p Dave
36  * Fixed multiplayer degenerate orientation case problem. Make sure warp
37  * effect never goes lower than LOD 1. 
38  * 
39  * 11    9/06/99 11:25a Mikek
40  * Decrease some settings for High detail level.
41  * 
42  * 10    8/05/99 2:05a Dave
43  * Whee.
44  * 
45  * 9     7/29/99 10:47p Dave
46  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
47  * 
48  * 8     7/29/99 12:05a Dave
49  * Nebula speed optimizations.
50  * 
51  * 7     6/22/99 7:03p Dave
52  * New detail options screen.
53  * 
54  * 6     6/16/99 4:06p Dave
55  * New pilot info popup. Added new draw-bitmap-as-poly function.
56  * 
57  * 5     5/24/99 5:45p Dave
58  * Added detail levels to the nebula, with a decent speedup. Split nebula
59  * lightning into its own section.
60  * 
61  * 4     11/30/98 1:07p Dave
62  * 16 bit conversion, first run.
63  * 
64  * 3     10/07/98 6:27p Dave
65  * Globalized mission and campaign file extensions. Removed Silent Threat
66  * special code. Moved \cache \players and \multidata into the \data
67  * directory.
68  * 
69  * 2     10/07/98 10:52a Dave
70  * Initial checkin.
71  * 
72  * 1     10/07/98 10:48a Dave
73  * 
74  * 38    9/21/98 8:46p Dave
75  * Put in special check in fred for identifying unknown ships.
76  * 
77  * 37    8/17/98 5:07p Dave
78  * First rev of corkscrewing missiles.
79  * 
80  * 36    5/13/98 11:34p Mike
81  * Model caching system.
82  * 
83  * 35    4/25/98 4:06p John
84  * Made defaults make a little more sense
85  * 
86  * 34    4/20/98 8:41p John
87  * Made debris culling actually reduce Glide texture resolution.
88  * 
89  * 33    4/12/98 9:56a John
90  * Made lighting detail flags work.   Made explosions cast light on
91  * highest.
92  * 
93  * 32    4/08/98 8:34p Lawrance
94  * Fix up how custom button works on the detail tab.
95  * 
96  * 31    4/01/98 5:34p John
97  * Made only the used POFs page in for a level.   Reduced some interp
98  * arrays.    Made custom detail level work differently.
99  * 
100  * 30    3/31/98 5:18p John
101  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
102  * bunch of debug stuff out of player file.  Made model code be able to
103  * unload models and malloc out only however many models are needed.
104  *  
105  * 
106  * 29    3/30/98 2:38p Mike
107  * Add asteroid_density to detail level support.
108  * No force explosion damage in training missions.
109  * Make cargo deathrolls shorter.
110  * 
111  * 28    3/24/98 8:16a John
112  * made highest detail different than next one down
113  * 
114  * 27    3/23/98 5:19p John
115  * Upped number of default detail levels to 4
116  * 
117  * 26    3/22/98 4:11p Andsager
118  * Remove global Freespace_running
119  * 
120  * 25    3/22/98 3:28p John
121  * Added in stippled alpha for lower details.  Made medium detail use
122  * engine glow.
123  * 
124  * 24    3/22/98 2:41p John
125  * Added lighting into the detail structure.
126  * 
127  * 23    3/22/98 11:06a John
128  * Changed default detail levels
129  * 
130  * 22    3/22/98 11:02a John
131  * Made a bunch of the detail levels actually do something
132  * 
133  * 21    3/22/98 9:53a John
134  * Added in first stage of new detail level stuff
135  * 
136  * 20    3/09/98 12:13a Andsager
137  * Add code to help find jumps in position.
138  * 
139  * 19    2/28/98 7:03p Lawrance
140  * get slew working in any view
141  * 
142  * 18    2/16/98 4:16p John
143  * Added loading animation
144  * 
145  * 17    2/10/98 9:06a John
146  * Added variables for restoring
147  * 
148  * 16    2/05/98 9:27p John
149  * took out ending min/max etc on monitor
150  * 
151  * 15    2/05/98 9:21p John
152  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
153  * game.
154  * 
155  * 14    2/03/98 9:25p John
156  * Upgraded Direct3D code to new version 5.0 code.  Separated the D3D code
157  * more.  Added a global variable D3D_enabled flag.
158  * 
159  * 13    1/17/98 12:17p John
160  * fixed erroneous print
161  * 
162  * 12    1/17/98 12:14p John
163  * Added loading... bar to freespace.
164  * 
165  * 11    1/11/98 2:15p John
166  * Changed a lot of stuff that had to do with bitmap loading.   Made cfile
167  * not do callbacks, I put that in global code.   Made only bitmaps that
168  * need to load for a level load.
169  * 
170  * 10    12/16/97 6:20p Hoffoss
171  * Added more debugging code for demos, and fixed a bug in demo
172  * recording/playback.
173  * 
174  * 9     12/05/97 3:46p John
175  * made ship thruster glow scale instead of being an animation.
176  * 
177  * 8     8/05/97 10:18a Lawrance
178  * my_rand() being used temporarily instead of rand()
179  * 
180  * 7     8/04/97 10:21a Dave
181  * Added Is_standalone global var
182  * 
183  * 6     6/24/97 6:21p John
184  * added detail flags.
185  * sped up motion debris system a bit.
186  * 
187  * 5     4/15/97 11:28p Mike
188  * External view system
189  * 
190  * 4     4/15/97 4:00p Mike
191  * Intermediate checkin caused by getting other files.  Working on camera
192  * slewing system.
193  * 
194  * 3     4/08/97 8:47a John
195  * Added a global varible for detail level
196  * 
197  * 2     4/01/97 11:07p Mike
198  * Clean up game sequencing functions.  Get rid of Multiplayer and add
199  * Game_mode.  Add SystemVars.cpp
200  * 
201  * 1     4/01/97 10:59p Mike
202  *
203  * $NoKeywords: $
204  */
205
206 #include "pstypes.h"
207 #include "systemvars.h"
208 #include "timer.h"
209 #include "neb.h"
210
211 fix Missiontime;
212 fix Frametime;
213 int     Framecount=0;
214
215 int Game_mode;
216
217 int Game_restoring = 0;         // If set, this means we are restoring data from disk
218
219 int     Viewer_mode;            //      Viewer's mode, see VM_xxxx flags.
220
221 // The detail level.  Anything below zero draws simple models earlier than it
222 // should.   Anything above zero draws higher detail models longer than it should.
223 // -2=lowest
224 // -1=low
225 // 0=normal (medium)    
226 // 1=high
227 // 2=extra high
228 int Game_detail_level = 0;
229 uint Game_detail_flags = DETAIL_DEFAULT;        // see systemvars.h for explanation
230
231 angles  Viewer_slew_angles;                     //      Angles of viewer relative to forward.
232 vei             Viewer_external_info;           //      Viewer angles to ship in external view.
233 vci             Viewer_chase_info;                      // View chase camera information
234
235 int Is_standalone;
236 int Rand_count;
237
238 int Interface_last_tick = -1;                   // last timer tick on flip
239
240 // for notifying players of unknown ship types
241 int Fred_found_unknown_ship_during_parsing = 0;
242
243 // If true, then we are using Direct3D hardware.  This is used for game type stuff
244 // that changes when you're using hardware.
245 int D3D_enabled = 0;                    
246
247 // Values used for noise for thruster animations
248 float Noise[NOISE_NUM_FRAMES] = { 
249         0.468225f,
250         0.168765f,
251         0.318945f,
252         0.292866f,
253         0.553357f,
254         0.468225f,
255         0.180456f,
256         0.418465f,
257         0.489958f,
258         1.000000f,
259         0.468225f,
260         0.599820f,
261         0.664718f,
262         0.294215f,
263         0.000000f
264 };
265
266
267 int myrand()
268 {
269         int rval;
270 #if MY_RAND_MAX != RAND_MAX
271         rval = rand() % (MY_RAND_MAX+1);
272 #else
273         rval = rand();
274 #endif
275         Rand_count++;
276 //      nprintf(("Alan","RAND: %d\n", rval));
277         return rval;
278 }
279
280
281 // Variables for the loading callback hooks
282 static int cf_timestamp = -1;
283 static void (*cf_callback)(int count) = NULL;
284 static int cf_in_callback = 0;  
285 static int cb_counter = 0;
286 static int cb_last_counter = 0;
287 static int cb_delta_step = -1;
288
289 // Call this with the name of a function.  That function will
290 // then get called around 10x per second.  The callback function
291 // gets passed a 'count' which is how many times game_busy has
292 // been called since the callback was set.   It gets called
293 // one last time with count=-1 when you turn off the callback
294 // by calling game_busy_callback(NULL).   Game_busy_callback
295 // returns the current count, so you can tell how many times
296 // game_busy got called.
297 int game_busy_callback( void (*callback)(int count), int delta_step )
298 {
299         if ( !callback ) {
300
301                 // Call it once more to finalize things
302                 cf_in_callback++;
303                 (*cf_callback)(-1);
304                 cf_in_callback--;
305
306                 cf_timestamp = -1;
307                 cf_callback = NULL;
308         } else {
309                 cb_counter = 0;
310                 cb_last_counter = 0;
311                 cb_delta_step = delta_step;
312                 cf_timestamp = timer_get_milliseconds()+(1000/10);
313                 cf_callback = callback;
314
315                 // Call it once
316                 cf_in_callback++;
317                 (*cf_callback)(0);              // pass 0 first time!
318                 cf_in_callback--;
319         
320         }
321
322         return cb_counter;
323 }
324
325 // Call whenever loading to display cursor
326 void game_busy()
327 {
328         if ( cf_in_callback != 0 ) return;      // don't call callback if we're already in it.
329         if ( cf_timestamp < 0 ) return;
330         if ( !cf_callback ) return;
331
332         cb_counter++;
333
334 //      mprintf(( "CB_COUNTER=%d\n", cb_counter ));
335
336         int t1 = timer_get_milliseconds();
337
338         if ( (t1 > cf_timestamp) || ((cb_counter>cb_last_counter+155)&&(cb_delta_step>0)) )     {
339                 cb_last_counter = cb_counter;
340                 cf_in_callback++;
341                 (*cf_callback)(cb_counter);
342                 cf_in_callback--;
343                 cf_timestamp = t1 + +(1000/10);
344         }
345 }
346
347 //======================== CODE TO MONITOR EVENTS ======================
348
349 #ifndef NDEBUG
350
351 #define MAX_MONITORS 64
352
353 static int Num_monitors = 0;
354 static monitor *Monitor[MAX_MONITORS];
355
356 monitor::monitor( const char *_name )
357 {
358         int i;
359
360         if ( Num_monitors >= MAX_MONITORS )     {
361                 Int3();                 // Too many monitor variables!! Increase MAX_MONITORS!!
362                 return;
363         }
364
365         for (i=0; i<Num_monitors; i++ ) {
366                 int ret  = stricmp( Monitor[i]->name, _name );
367
368                 if ( ret == 0)  {
369                         Int3();         // This monitor variable already exists!!!! 
370                         return;
371                 } else if ( ret > 0 )   {
372                         break;          // Insert it here
373
374                 } else if ( ret < 0 )   {
375                         // do nothing
376                 }
377         }
378
379         if ( i < Num_monitors ) {
380                 // Insert it at element i
381                 int j;
382                 for (j=Num_monitors; j>i; j-- ) {
383                         Monitor[j] = Monitor[j-1];
384                 }
385                 Monitor[i] = this;              
386                 Num_monitors++;
387         } else {
388                 Monitor[Num_monitors] = this;           
389                 Num_monitors++;
390         }
391
392         name = (char*)_name;
393         value = 0;
394 }
395
396
397 int Monitor_inited = 0;
398 char Monitor_filename[128];
399 fix monitor_last_time = -1;
400
401 DCF(monitor,"Monitors game performace")
402 {
403         if ( Dc_command )       {
404                 dc_get_arg(ARG_STRING|ARG_NONE);
405                 if ( Dc_arg_type == ARG_NONE )  {
406                         if ( Monitor_inited )   {
407                                 Monitor_inited = 0;
408
409 /*
410                                 FILE *fp = fopen( Monitor_filename, "at" );
411                                 if ( fp )       {
412                                         fprintf( fp, "\n\n" );
413                                         fprintf( fp, "Name\tMin\tMax\tAvg\n" );
414                                         for (int i=0; i<Num_monitors; i++ )     {
415                                                 if ( Monitor[i]->cnt > 0 )      {
416                                                         fprintf( fp, "%s\t%d\t%d\t%d\n", Monitor[i]->name, Monitor[i]->min, Monitor[i]->max, Monitor[i]->sum / Monitor[i]->cnt  );
417                                                 } else {
418                                                         fprintf( fp, "%s\t%d\t%d\t?\n", Monitor[i]->name, Monitor[i]->min, Monitor[i]->max );
419                                                 }
420                                         }
421                                         fclose(fp);
422                                 }
423 */
424
425                                 dc_printf( "Monitor to file '%s' turned off\n", Monitor_filename );
426                         } else {
427                                 dc_printf( "Monitor isn't on\n" );
428                         }
429                 } else {
430                         if ( Monitor_inited )   {
431                                 dc_printf( "Monitor already on\n" );
432                         } else {
433                                 Monitor_inited = 1;
434
435                                 strcpy( Monitor_filename, Dc_arg );
436
437                                 // Reset them all
438                                 int i;
439                                 for (i=0; i<Num_monitors; i++ ) {
440                                         Monitor[i]->value = 0;
441                                         Monitor[i]->sum = 0;
442                                         Monitor[i]->cnt = 0;
443                                         Monitor[i]->min = 0;
444                                         Monitor[i]->max = 0;
445                                 }
446
447                                 FILE *fp = fopen( Monitor_filename, "wt" );
448                                 if ( fp )       {
449                                         for (i=0; i<Num_monitors; i++ ) {
450                                                 if ( i > 0 )    {
451                                                         fprintf( fp, "\t" );
452                                                 }
453                                                 fprintf( fp, "%s", Monitor[i]->name );
454                                         
455                                         }
456                                         fprintf( fp, "\n" );
457                                         fclose(fp);
458                                 }
459                                 dc_printf( "Monitor outputting to file '%s'\n", Monitor_filename );
460                                 monitor_last_time = -1;
461                         }
462                 }
463         }
464         if ( Dc_help )  {
465                 dc_printf( "Usage: monitor filename\nOutputs monitoring info to filename. No filename turns it off\n" );
466         }
467         
468 }
469
470
471 MONITOR(FrameRateX100);
472
473 void monitor_update()
474 {
475         int i;
476         FILE * fp;
477
478         fix this_time = timer_get_fixed_seconds();
479         fix frametime;
480
481         if ( monitor_last_time != -1 )  {
482                 frametime = this_time - monitor_last_time;
483         } else {
484                 frametime = 0;
485         }
486
487         if ( frametime > 0 )    {
488                 MONITOR_INC(FrameRateX100, (F1_0*100) / frametime );
489         } else {
490                 MONITOR_INC(FrameRateX100, 0 );
491         }
492
493                 
494         if ( !Monitor_inited )  {
495                 return;
496         }
497
498         if ( frametime != 0 )   {
499                 fp = fopen( Monitor_filename, "at" );
500                 if ( fp )       {
501
502                         for (i=0; i<Num_monitors; i++ ) {
503                                 if (i>0) fprintf( fp, "\t" );
504                                 fprintf( fp, "%d", Monitor[i]->value );
505                         }
506                         fprintf( fp, "\n" );
507                         fclose(fp);
508                 }
509
510                 for (i=0; i<Num_monitors; i++ ) {
511
512                         // Record stats
513                         Monitor[i]->sum += Monitor[i]->value;
514
515                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value < Monitor[i]->min ))  {
516                                 Monitor[i]->min = Monitor[i]->value;
517                         }
518
519                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value > Monitor[i]->max ))  {
520                                 Monitor[i]->max = Monitor[i]->value;
521                         }
522
523                         Monitor[i]->cnt++;
524
525                         //      Reset the value
526                         Monitor[i]->value = 0;
527                 }
528         } else {
529                 for (i=0; i<Num_monitors; i++ ) {
530                         //      Reset the value
531                         Monitor[i]->value = 0;
532                 }
533         }
534
535         monitor_last_time = timer_get_fixed_seconds();
536
537 }
538 #endif  //NDEBUG
539
540
541 #if MAX_DETAIL_LEVEL != 4
542 #error MAX_DETAIL_LEVEL is assumed to be 4 in SystemVars.cpp
543 #endif
544
545 #if NUM_DEFAULT_DETAIL_LEVELS != 4
546 #error NUM_DEFAULT_DETAIL_LEVELS is assumed to be 4 in SystemVars.cpp
547 #endif
548
549 // Detail level stuff
550 detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
551         {                               // Low
552                 0,                      // setting
553                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
554                 0,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
555                 0,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
556                 0,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
557                 0,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
558                 0,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
559                 0,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
560                 0,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
561                 2,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
562
563                                         // ====  Booleans ====
564                 0,                      //      targetview_model;                       // 0=off, 1=on          
565                 0,                      //      planets_suns;                           // 0=off, 1=on          
566                 0,                      // weapon_extras
567 #ifdef MAKE_FS1
568                 0,                      // engine_glows;
569 #endif
570         },
571         {                               // Medium
572                 1,                      // setting
573                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
574                 1,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
575                 1,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
576                 1,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
577                 2,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
578                 2,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
579                 2,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
580                 1,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
581                 3,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
582
583                 // ====  Booleans ====
584                 1,                      //      targetview_model;                       // 0=off, 1=on          
585                 1,                      //      planets_suns;                           // 0=off, 1=on
586                 1,                      // weapon extras                                
587 #ifdef MAKE_FS1
588                 1,                      // engine_glows;
589 #endif
590         },
591         {                               // High level
592                 2,                      // setting
593                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
594                 2,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
595                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
596                 3,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
597                 3,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
598                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
599                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
600                 3,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
601                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
602
603                                                                                 // ====  Booleans ====
604                 1,                      //      targetview_model;                       // 0=off, 1=on          
605                 1,                      //      planets_suns;                           // 0=off, 1=on
606                 1,                      // weapon_extras
607 #ifdef MAKE_FS1
608                 1,                      // engine_glows;
609 #endif
610         },
611         {                               // Highest level
612                 3,                      // setting
613                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
614                 3,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
615                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
616                 4,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
617                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
618                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
619                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
620                 4,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
621                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
622
623                                                                                 // ====  Booleans ====
624                 1,                      //      targetview_model;                       // 0=off, 1=on          
625                 1,                      //      planets_suns;                           // 0=off, 1=on
626                 1,                      // weapon_extras
627 #ifdef MAKE_FS1
628                 1,                      // engine_glows;
629 #endif
630         },
631 };
632
633
634 // Global used to access detail levels in game and libs
635 detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS-1];
636
637 // Call this with:
638 // 0 - lowest
639 // NUM_DETAIL_LEVELS - highest
640 // To set the parameters in Detail to some set of defaults
641 void detail_level_set(int level)
642 {
643         if ( level < 0 )        {
644                 Detail.setting = -1;
645                 return;
646         }
647         Assert( level >= 0 );
648         Assert( level < NUM_DEFAULT_DETAIL_LEVELS );
649
650         Detail = Detail_defaults[level];
651
652         // reset nebula stuff
653         neb2_set_detail_level(level);
654 }
655
656 // Returns the current detail level or -1 if custom.
657 int current_detail_level()
658 {
659 //      return Detail.setting;
660         int i;
661         int match = -1;
662
663         for (i=0; i<NUM_DEFAULT_DETAIL_LEVELS; i++ )    {
664                 if ( Detail.setting == -1 ) {
665                         // in the case of a custom detail level, return it's closest match
666                         if ( (Detail.nebula_detail >= Detail_defaults[i].nebula_detail) &&
667                                  (Detail.detail_distance >= Detail_defaults[i].detail_distance) &&
668                                  (Detail.hardware_textures >= Detail_defaults[i].hardware_textures) &&
669                                  (Detail.shield_effects >= Detail_defaults[i].shield_effects) &&
670                                  (Detail.lighting >= Detail_defaults[i].lighting) &&
671                                  (Detail.planets_suns == Detail_defaults[i].planets_suns) &&
672                                  (Detail.weapon_extras == Detail_defaults[i].weapon_extras) )
673                         {
674                                 match = i; // we will keep whatever the highest value is
675                         }
676                 } else if ( memcmp( &Detail, &Detail_defaults[i], sizeof(detail_levels) )==0 )  {
677                         return i;
678                 }
679         }
680
681         return match;
682 }
683
684 #ifndef NDEBUG
685 DCF(detail_level,"Change the detail level")
686 {
687         if ( Dc_command )       {
688                 dc_get_arg(ARG_INT|ARG_NONE);
689                 if ( Dc_arg_type & ARG_NONE )   {
690                         Game_detail_level = 0;
691                         dc_printf( "Detail level reset\n" );
692                 }
693                 if ( Dc_arg_type & ARG_INT )    {
694                         Game_detail_level = Dc_arg_int;
695                 }
696         }
697
698         if ( Dc_help )  
699                 dc_printf( "Usage: detail_level [n]\nn is detail level. 0 normal, - lower, + higher, -2 to 2 usually\nNo parameter resets it to default.\n" );
700
701         if ( Dc_status )                                
702                 dc_printf("Detail level set to %d\n", Game_detail_level);
703 }
704
705 DCF(detail, "Turns on/off parts of the game for speed testing" )
706 {
707         if ( Dc_command )       {
708                 dc_get_arg(ARG_INT|ARG_NONE);
709                 if ( Dc_arg_type & ARG_NONE )   {
710                         if ( Game_detail_flags == DETAIL_DEFAULT )      {
711                                 Game_detail_flags = DETAIL_FLAG_CLEAR;
712                                 dc_printf( "Detail flags set lowest (except has screen clear)\n" );
713                         } else {
714                                 Game_detail_flags = DETAIL_DEFAULT;
715                                 dc_printf( "Detail flags set highest\n" );
716                         }
717                 }
718                 if ( Dc_arg_type & ARG_INT )    {
719                         Game_detail_flags ^= Dc_arg_int;
720                 }
721         }
722
723         if ( Dc_help )  {
724                 dc_printf( "Usage: detail [n]\nn is detail bit to toggle.\n" );
725                 dc_printf( "   1: draw the stars\n" );
726                 dc_printf( "   2: draw the nebulas\n" );
727                 dc_printf( "   4: draw the motion debris\n" );
728                 dc_printf( "   8: draw planets\n" );
729                 dc_printf( "  16: draw models not as blobs\n" );
730                 dc_printf( "  32: draw lasers not as pixels\n" );
731                 dc_printf( "  64: clear screen background after each frame\n" );
732                 dc_printf( " 128: draw hud stuff\n" );
733                 dc_printf( " 256: draw fireballs\n" );
734                 dc_printf( " 512: do collision detection\n" );
735         }
736
737         if ( Dc_status )        {
738                 dc_printf("Detail flags set to 0x%08x\n", Game_detail_flags);
739                 dc_printf( "   1: draw the stars: %s\n", (Game_detail_flags&1?"on":"off") );
740                 dc_printf( "   2: draw the nebulas: %s\n", (Game_detail_flags&2?"on":"off") );
741                 dc_printf( "   4: draw the motion debris: %s\n", (Game_detail_flags&4?"on":"off")  );
742                 dc_printf( "   8: draw planets: %s\n", (Game_detail_flags&8?"on":"off")  );
743                 dc_printf( "  16: draw models not as blobs: %s\n", (Game_detail_flags&16?"on":"off")  );
744                 dc_printf( "  32: draw lasers not as pixels: %s\n", (Game_detail_flags&32?"on":"off")  );
745                 dc_printf( "  64: clear screen background after each frame: %s\n", (Game_detail_flags&64?"on":"off")  );
746                 dc_printf( " 128: draw hud stuff: %s\n", (Game_detail_flags&128?"on":"off")  );
747                 dc_printf( " 256: draw fireballs: %s\n", (Game_detail_flags&256?"on":"off")  );
748                 dc_printf( " 512: do collision detection: %s\n", (Game_detail_flags&512?"on":"off")  );
749         }
750 }
751 #endif