]> icculus.org git repositories - taylor/freespace2.git/blob - src/globalincs/systemvars.cpp
safer strings using SDL string functions
[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 // Values used for noise for thruster animations
244 float Noise[NOISE_NUM_FRAMES] = { 
245         0.468225f,
246         0.168765f,
247         0.318945f,
248         0.292866f,
249         0.553357f,
250         0.468225f,
251         0.180456f,
252         0.418465f,
253         0.489958f,
254         1.000000f,
255         0.468225f,
256         0.599820f,
257         0.664718f,
258         0.294215f,
259         0.000000f
260 };
261
262
263 int myrand()
264 {
265         int rval;
266 #if MY_RAND_MAX != RAND_MAX
267         rval = rand() % (MY_RAND_MAX+1);
268 #else
269         rval = rand();
270 #endif
271         Rand_count++;
272 //      nprintf(("Alan","RAND: %d\n", rval));
273         return rval;
274 }
275
276
277 // Variables for the loading callback hooks
278 static int cf_timestamp = -1;
279 static void (*cf_callback)(int count) = NULL;
280 static int cf_in_callback = 0;  
281 static int cb_counter = 0;
282 static int cb_last_counter = 0;
283 static int cb_delta_step = -1;
284
285 // Call this with the name of a function.  That function will
286 // then get called around 10x per second.  The callback function
287 // gets passed a 'count' which is how many times game_busy has
288 // been called since the callback was set.   It gets called
289 // one last time with count=-1 when you turn off the callback
290 // by calling game_busy_callback(NULL).   Game_busy_callback
291 // returns the current count, so you can tell how many times
292 // game_busy got called.
293 int game_busy_callback( void (*callback)(int count), int delta_step )
294 {
295         if ( !callback ) {
296
297                 // Call it once more to finalize things
298                 cf_in_callback++;
299                 (*cf_callback)(-1);
300                 cf_in_callback--;
301
302                 cf_timestamp = -1;
303                 cf_callback = NULL;
304         } else {
305                 cb_counter = 0;
306                 cb_last_counter = 0;
307                 cb_delta_step = delta_step;
308                 cf_timestamp = timer_get_milliseconds()+(1000/10);
309                 cf_callback = callback;
310
311                 // Call it once
312                 cf_in_callback++;
313                 (*cf_callback)(0);              // pass 0 first time!
314                 cf_in_callback--;
315         
316         }
317
318         return cb_counter;
319 }
320
321 // Call whenever loading to display cursor
322 void game_busy()
323 {
324         if ( cf_in_callback != 0 ) return;      // don't call callback if we're already in it.
325         if ( cf_timestamp < 0 ) return;
326         if ( !cf_callback ) return;
327
328         cb_counter++;
329
330 //      mprintf(( "CB_COUNTER=%d\n", cb_counter ));
331
332         int t1 = timer_get_milliseconds();
333
334         if ( (t1 > cf_timestamp) || ((cb_counter>cb_last_counter+155)&&(cb_delta_step>0)) )     {
335                 cb_last_counter = cb_counter;
336                 cf_in_callback++;
337                 (*cf_callback)(cb_counter);
338                 cf_in_callback--;
339                 cf_timestamp = t1 + +(1000/10);
340         }
341 }
342
343 //======================== CODE TO MONITOR EVENTS ======================
344
345 #ifndef NDEBUG
346
347 #define MAX_MONITORS 64
348
349 static int Num_monitors = 0;
350 static monitor *Monitor[MAX_MONITORS];
351
352 monitor::monitor( const char *_name )
353 {
354         int i;
355
356         if ( Num_monitors >= MAX_MONITORS )     {
357                 Int3();                 // Too many monitor variables!! Increase MAX_MONITORS!!
358                 return;
359         }
360
361         for (i=0; i<Num_monitors; i++ ) {
362                 int ret  = SDL_strcasecmp( Monitor[i]->name, _name );
363
364                 if ( ret == 0)  {
365                         Int3();         // This monitor variable already exists!!!! 
366                         return;
367                 } else if ( ret > 0 )   {
368                         break;          // Insert it here
369
370                 } else if ( ret < 0 )   {
371                         // do nothing
372                 }
373         }
374
375         if ( i < Num_monitors ) {
376                 // Insert it at element i
377                 int j;
378                 for (j=Num_monitors; j>i; j-- ) {
379                         Monitor[j] = Monitor[j-1];
380                 }
381                 Monitor[i] = this;              
382                 Num_monitors++;
383         } else {
384                 Monitor[Num_monitors] = this;           
385                 Num_monitors++;
386         }
387
388         name = (char*)_name;
389         value = 0;
390 }
391
392
393 int Monitor_inited = 0;
394 char Monitor_filename[128];
395 fix monitor_last_time = -1;
396
397 DCF(monitor,"Monitors game performace")
398 {
399         if ( Dc_command )       {
400                 dc_get_arg(ARG_STRING|ARG_NONE);
401                 if ( Dc_arg_type == ARG_NONE )  {
402                         if ( Monitor_inited )   {
403                                 Monitor_inited = 0;
404
405 /*
406                                 FILE *fp = fopen( Monitor_filename, "at" );
407                                 if ( fp )       {
408                                         fprintf( fp, "\n\n" );
409                                         fprintf( fp, "Name\tMin\tMax\tAvg\n" );
410                                         for (int i=0; i<Num_monitors; i++ )     {
411                                                 if ( Monitor[i]->cnt > 0 )      {
412                                                         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  );
413                                                 } else {
414                                                         fprintf( fp, "%s\t%d\t%d\t?\n", Monitor[i]->name, Monitor[i]->min, Monitor[i]->max );
415                                                 }
416                                         }
417                                         fclose(fp);
418                                 }
419 */
420
421                                 dc_printf( "Monitor to file '%s' turned off\n", Monitor_filename );
422                         } else {
423                                 dc_printf( "Monitor isn't on\n" );
424                         }
425                 } else {
426                         if ( Monitor_inited )   {
427                                 dc_printf( "Monitor already on\n" );
428                         } else {
429                                 Monitor_inited = 1;
430
431                                 SDL_strlcpy( Monitor_filename, Dc_arg, sizeof(Monitor_filename) );
432
433                                 // Reset them all
434                                 int i;
435                                 for (i=0; i<Num_monitors; i++ ) {
436                                         Monitor[i]->value = 0;
437                                         Monitor[i]->sum = 0;
438                                         Monitor[i]->cnt = 0;
439                                         Monitor[i]->min = 0;
440                                         Monitor[i]->max = 0;
441                                 }
442
443                                 FILE *fp = fopen( Monitor_filename, "wt" );
444                                 if ( fp )       {
445                                         for (i=0; i<Num_monitors; i++ ) {
446                                                 if ( i > 0 )    {
447                                                         fprintf( fp, "\t" );
448                                                 }
449                                                 fprintf( fp, "%s", Monitor[i]->name );
450                                         
451                                         }
452                                         fprintf( fp, "\n" );
453                                         fclose(fp);
454                                 }
455                                 dc_printf( "Monitor outputting to file '%s'\n", Monitor_filename );
456                                 monitor_last_time = -1;
457                         }
458                 }
459         }
460         if ( Dc_help )  {
461                 dc_printf( "Usage: monitor filename\nOutputs monitoring info to filename. No filename turns it off\n" );
462         }
463         
464 }
465
466
467 MONITOR(FrameRateX100);
468
469 void monitor_update()
470 {
471         int i;
472         FILE * fp;
473
474         fix this_time = timer_get_fixed_seconds();
475         fix frametime;
476
477         if ( monitor_last_time != -1 )  {
478                 frametime = this_time - monitor_last_time;
479         } else {
480                 frametime = 0;
481         }
482
483         if ( frametime > 0 )    {
484                 MONITOR_INC(FrameRateX100, (F1_0*100) / frametime );
485         } else {
486                 MONITOR_INC(FrameRateX100, 0 );
487         }
488
489                 
490         if ( !Monitor_inited )  {
491                 return;
492         }
493
494         if ( frametime != 0 )   {
495                 fp = fopen( Monitor_filename, "at" );
496                 if ( fp )       {
497
498                         for (i=0; i<Num_monitors; i++ ) {
499                                 if (i>0) fprintf( fp, "\t" );
500                                 fprintf( fp, "%d", Monitor[i]->value );
501                         }
502                         fprintf( fp, "\n" );
503                         fclose(fp);
504                 }
505
506                 for (i=0; i<Num_monitors; i++ ) {
507
508                         // Record stats
509                         Monitor[i]->sum += Monitor[i]->value;
510
511                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value < Monitor[i]->min ))  {
512                                 Monitor[i]->min = Monitor[i]->value;
513                         }
514
515                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value > Monitor[i]->max ))  {
516                                 Monitor[i]->max = Monitor[i]->value;
517                         }
518
519                         Monitor[i]->cnt++;
520
521                         //      Reset the value
522                         Monitor[i]->value = 0;
523                 }
524         } else {
525                 for (i=0; i<Num_monitors; i++ ) {
526                         //      Reset the value
527                         Monitor[i]->value = 0;
528                 }
529         }
530
531         monitor_last_time = timer_get_fixed_seconds();
532
533 }
534 #endif  //NDEBUG
535
536
537 #if MAX_DETAIL_LEVEL != 4
538 #error MAX_DETAIL_LEVEL is assumed to be 4 in SystemVars.cpp
539 #endif
540
541 #if NUM_DEFAULT_DETAIL_LEVELS != 4
542 #error NUM_DEFAULT_DETAIL_LEVELS is assumed to be 4 in SystemVars.cpp
543 #endif
544
545 // Detail level stuff
546 detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
547         {                               // Low
548                 0,                      // setting
549                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
550                 0,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
551                 0,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
552                 0,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
553                 0,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
554                 0,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
555                 0,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
556                 0,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
557                 2,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
558
559                                         // ====  Booleans ====
560                 0,                      //      targetview_model;                       // 0=off, 1=on          
561                 0,                      //      planets_suns;                           // 0=off, 1=on          
562                 0,                      // weapon_extras
563 #ifdef MAKE_FS1
564                 0,                      // engine_glows;
565 #endif
566         },
567         {                               // Medium
568                 1,                      // setting
569                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
570                 1,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
571                 1,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
572                 1,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
573                 2,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
574                 2,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
575                 2,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
576                 1,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
577                 3,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
578
579                 // ====  Booleans ====
580                 1,                      //      targetview_model;                       // 0=off, 1=on          
581                 1,                      //      planets_suns;                           // 0=off, 1=on
582                 1,                      // weapon extras                                
583 #ifdef MAKE_FS1
584                 1,                      // engine_glows;
585 #endif
586         },
587         {                               // High level
588                 2,                      // setting
589                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
590                 2,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
591                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
592                 3,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
593                 3,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
594                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
595                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
596                 3,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
597                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
598
599                                                                                 // ====  Booleans ====
600                 1,                      //      targetview_model;                       // 0=off, 1=on          
601                 1,                      //      planets_suns;                           // 0=off, 1=on
602                 1,                      // weapon_extras
603 #ifdef MAKE_FS1
604                 1,                      // engine_glows;
605 #endif
606         },
607         {                               // Highest level
608                 3,                      // setting
609                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
610                 3,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
611                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
612                 4,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
613                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
614                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
615                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
616                 4,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
617                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
618
619                                                                                 // ====  Booleans ====
620                 1,                      //      targetview_model;                       // 0=off, 1=on          
621                 1,                      //      planets_suns;                           // 0=off, 1=on
622                 1,                      // weapon_extras
623 #ifdef MAKE_FS1
624                 1,                      // engine_glows;
625 #endif
626         },
627 };
628
629
630 // Global used to access detail levels in game and libs
631 detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS-1];
632
633 // Call this with:
634 // 0 - lowest
635 // NUM_DETAIL_LEVELS - highest
636 // To set the parameters in Detail to some set of defaults
637 void detail_level_set(int level)
638 {
639         if ( level < 0 )        {
640                 Detail.setting = -1;
641                 return;
642         }
643         SDL_assert( level >= 0 );
644         SDL_assert( level < NUM_DEFAULT_DETAIL_LEVELS );
645
646         Detail = Detail_defaults[level];
647
648         // reset nebula stuff
649         neb2_set_detail_level(level);
650 }
651
652 // Returns the current detail level or -1 if custom.
653 int current_detail_level()
654 {
655 //      return Detail.setting;
656         int i;
657         int match = -1;
658
659         for (i=0; i<NUM_DEFAULT_DETAIL_LEVELS; i++ )    {
660                 if ( Detail.setting == -1 ) {
661                         // in the case of a custom detail level, return it's closest match
662                         if ( (Detail.nebula_detail >= Detail_defaults[i].nebula_detail) &&
663                                  (Detail.detail_distance >= Detail_defaults[i].detail_distance) &&
664                                  (Detail.hardware_textures >= Detail_defaults[i].hardware_textures) &&
665                                  (Detail.shield_effects >= Detail_defaults[i].shield_effects) &&
666                                  (Detail.lighting >= Detail_defaults[i].lighting) &&
667                                  (Detail.planets_suns == Detail_defaults[i].planets_suns) &&
668                                  (Detail.weapon_extras == Detail_defaults[i].weapon_extras) )
669                         {
670                                 match = i; // we will keep whatever the highest value is
671                         }
672                 } else if ( memcmp( &Detail, &Detail_defaults[i], sizeof(detail_levels) )==0 )  {
673                         return i;
674                 }
675         }
676
677         return match;
678 }
679
680 #ifndef NDEBUG
681 DCF(detail_level,"Change the detail level")
682 {
683         if ( Dc_command )       {
684                 dc_get_arg(ARG_INT|ARG_NONE);
685                 if ( Dc_arg_type & ARG_NONE )   {
686                         Game_detail_level = 0;
687                         dc_printf( "Detail level reset\n" );
688                 }
689                 if ( Dc_arg_type & ARG_INT )    {
690                         Game_detail_level = Dc_arg_int;
691                 }
692         }
693
694         if ( Dc_help )  
695                 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" );
696
697         if ( Dc_status )                                
698                 dc_printf("Detail level set to %d\n", Game_detail_level);
699 }
700
701 DCF(detail, "Turns on/off parts of the game for speed testing" )
702 {
703         if ( Dc_command )       {
704                 dc_get_arg(ARG_INT|ARG_NONE);
705                 if ( Dc_arg_type & ARG_NONE )   {
706                         if ( Game_detail_flags == DETAIL_DEFAULT )      {
707                                 Game_detail_flags = DETAIL_FLAG_CLEAR;
708                                 dc_printf( "Detail flags set lowest (except has screen clear)\n" );
709                         } else {
710                                 Game_detail_flags = DETAIL_DEFAULT;
711                                 dc_printf( "Detail flags set highest\n" );
712                         }
713                 }
714                 if ( Dc_arg_type & ARG_INT )    {
715                         Game_detail_flags ^= Dc_arg_int;
716                 }
717         }
718
719         if ( Dc_help )  {
720                 dc_printf( "Usage: detail [n]\nn is detail bit to toggle.\n" );
721                 dc_printf( "   1: draw the stars\n" );
722                 dc_printf( "   2: draw the nebulas\n" );
723                 dc_printf( "   4: draw the motion debris\n" );
724                 dc_printf( "   8: draw planets\n" );
725                 dc_printf( "  16: draw models not as blobs\n" );
726                 dc_printf( "  32: draw lasers not as pixels\n" );
727                 dc_printf( "  64: clear screen background after each frame\n" );
728                 dc_printf( " 128: draw hud stuff\n" );
729                 dc_printf( " 256: draw fireballs\n" );
730                 dc_printf( " 512: do collision detection\n" );
731         }
732
733         if ( Dc_status )        {
734                 dc_printf("Detail flags set to 0x%08x\n", Game_detail_flags);
735                 dc_printf( "   1: draw the stars: %s\n", (Game_detail_flags&1?"on":"off") );
736                 dc_printf( "   2: draw the nebulas: %s\n", (Game_detail_flags&2?"on":"off") );
737                 dc_printf( "   4: draw the motion debris: %s\n", (Game_detail_flags&4?"on":"off")  );
738                 dc_printf( "   8: draw planets: %s\n", (Game_detail_flags&8?"on":"off")  );
739                 dc_printf( "  16: draw models not as blobs: %s\n", (Game_detail_flags&16?"on":"off")  );
740                 dc_printf( "  32: draw lasers not as pixels: %s\n", (Game_detail_flags&32?"on":"off")  );
741                 dc_printf( "  64: clear screen background after each frame: %s\n", (Game_detail_flags&64?"on":"off")  );
742                 dc_printf( " 128: draw hud stuff: %s\n", (Game_detail_flags&128?"on":"off")  );
743                 dc_printf( " 256: draw fireballs: %s\n", (Game_detail_flags&256?"on":"off")  );
744                 dc_printf( " 512: do collision detection: %s\n", (Game_detail_flags&512?"on":"off")  );
745         }
746 }
747 #endif