home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / newmenu.c < prev    next >
Text File  |  1998-06-08  |  59KB  |  2,167 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/main/rcs/newmenu.c $
  15.  * $Revision: 2.8 $
  16.  * $Author: john $
  17.  * $Date: 1995/05/26 16:16:28 $
  18.  * 
  19.  * Routines for menus.
  20.  * 
  21.  * $Log: newmenu.c $
  22.  * Revision 2.8  1995/05/26  16:16:28  john
  23.  * Split SATURN into define's for requiring cd, using cd, etc.
  24.  * Also started adding all the Rockwell stuff.
  25.  * 
  26.  * Revision 2.7  1995/04/23  14:54:17  john
  27.  * Fixed bug with background breaking in first menu.
  28.  * 
  29.  * Revision 2.6  1995/03/21  14:38:46  john
  30.  * Ifdef'd out the NETWORK code.
  31.  * 
  32.  * Revision 2.5  1995/03/15  14:33:29  john
  33.  * Added code to force the Descent CD-rom in the drive.
  34.  * 
  35.  * Revision 2.4  1995/03/14  18:24:28  john
  36.  * Force Destination Saturn to use CD-ROM drive.
  37.  * 
  38.  * Revision 2.3  1995/03/14  16:22:23  john
  39.  * Added cdrom alternate directory stuff.
  40.  * 
  41.  * Revision 2.2  1995/03/06  18:30:51  john
  42.  * Fixed bug with newmenu trashing editor font.
  43.  * 
  44.  * Revision 2.1  1995/03/06  15:23:17  john
  45.  * New screen techniques.
  46.  * 
  47.  * Revision 2.0  1995/02/27  11:27:55  john
  48.  * New version 2.0, which has no anonymous unions, builds with
  49.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  50.  * 
  51.  * Revision 1.129  1995/02/11  16:19:56  john
  52.  * Added code to make the default mission be the one last played.
  53.  * 
  54.  * Revision 1.128  1995/02/02  19:41:33  john
  55.  * Added 10 save game slots.
  56.  * 
  57.  * Revision 1.127  1995/02/01  18:13:52  john
  58.  * Fixed some constants.
  59.  * 
  60.  * Revision 1.126  1995/02/01  18:04:01  yuan
  61.  * Added 50 characters to list.
  62.  * 
  63.  * Revision 1.125  1995/02/01  13:39:35  john
  64.  * Made menu text that changes not overwrite.
  65.  * 
  66.  * Revision 1.124  1995/01/31  10:47:57  john
  67.  * Added menu that you can specify the width of the menu.
  68.  * 
  69.  * Revision 1.123  1995/01/28  17:18:12  john
  70.  * Added file list box.
  71.  * 
  72.  * Revision 1.122  1995/01/27  17:15:55  john
  73.  * Made prev comment actually work.
  74.  * 
  75.  * Revision 1.121  1995/01/27  16:49:03  john
  76.  * *** empty log message ***
  77.  * 
  78.  * Revision 1.120  1995/01/27  16:46:40  john
  79.  * Made so that input_menu only clears text if -empty-.
  80.  * 
  81.  * Revision 1.119  1995/01/27  15:25:04  john
  82.  * Delete saved game when deleteing a pilot file.
  83.  * 
  84.  * Revision 1.118  1995/01/25  16:36:09  john
  85.  * Made so that when you hit enter during
  86.  * game save, -empty- goes away.
  87.  * 
  88.  * Revision 1.117  1995/01/24  16:59:30  john
  89.  * took out mono debugging text.
  90.  * 
  91.  * Revision 1.116  1995/01/24  16:23:16  john
  92.  * Fixed some bugs with listboxes.
  93.  * 
  94.  * Revision 1.115  1995/01/23  23:47:36  matt
  95.  * Made keypad enter work in menus
  96.  * 
  97.  * Revision 1.114  1995/01/23  19:29:59  john
  98.  * Added scrolling listbox menus.
  99.  * 
  100.  * Revision 1.113  1995/01/19  12:33:34  john
  101.  * Made keys jump to sliders, etc in menus.
  102.  * 
  103.  * Revision 1.112  1995/01/15  14:33:08  rob
  104.  * Fixed problem with nested nm_messageboxes.
  105.  * 
  106.  * Revision 1.111  1995/01/03  17:33:40  john
  107.  * Made scrolling textbox. Used it for scores cool saying.
  108.  * 
  109.  * Revision 1.110  1994/12/28  10:42:58  john
  110.  * More VFX tweaking.
  111.  * 
  112.  * Revision 1.109  1994/12/28  10:26:39  john
  113.  * Fixed some VFX problems.
  114.  * 
  115.  * Revision 1.108  1994/12/15  23:18:10  john
  116.  * Added fix so that VFX mode doesn't hang.
  117.  * 
  118.  * Revision 1.107  1994/12/15  12:19:55  john
  119.  * Made menu use clipped bitblt functions.
  120.  * 
  121.  * Revision 1.106  1994/12/09  00:41:30  mike
  122.  * fix hang in automap print screen
  123.  * 
  124.  * Revision 1.105  1994/12/08  10:01:34  john
  125.  * Changed the way the player callsign stuff works.
  126.  * 
  127.  * Revision 1.104  1994/12/04  15:34:30  john
  128.  * Fixed bug with newmenu not restoring font properly.
  129.  * 
  130.  * Revision 1.103  1994/12/03  17:47:09  john
  131.  * Fixed bug that didn't free filename mem when not .plr files found.
  132.  * 
  133.  * Revision 1.102  1994/12/03  15:06:15  john
  134.  * If no pilot exists, bring up box asking for name.
  135.  * 
  136.  * Revision 1.101  1994/12/03  11:04:02  john
  137.  * Changed newmenu code a bit to fix bug with bogus
  138.  * backgrounds occcasionally.
  139.  * 
  140.  * Revision 1.100  1994/12/01  20:15:48  yuan
  141.  * Localization.
  142.  * 
  143.  * Revision 1.99  1994/12/01  10:33:28  john
  144.  * Fixed bug with large menu backgrounds not drawing correctly.
  145.  * 
  146.  * Revision 1.98  1994/12/01  02:41:56  john
  147.  * Fixed warnining.
  148.  * 
  149.  * Revision 1.97  1994/11/30  22:52:43  john
  150.  * Fixed bug in code that made the backgrounds behind menus.
  151.  * 
  152.  * Revision 1.96  1994/11/30  19:47:42  john
  153.  * Added a check for out o' memory when mallocing background.
  154.  * 
  155.  * Revision 1.95  1994/11/30  19:39:10  john
  156.  * ..
  157.  * 
  158.  * Revision 1.94  1994/11/30  19:38:27  john
  159.  * fixed bug with previous.
  160.  * 
  161.  * Revision 1.93  1994/11/30  19:36:47  john
  162.  * Made Gravis Ultrasound work again.  Made the scores blink
  163.  * at a constant rate.  Revamped the newmenu background storage,
  164.  * which hopefully fixed some bugs.  Made menus in ame not pause
  165.  * sound, except for the pause key.               ^== Game!
  166.  * 
  167.  * Revision 1.92  1994/11/30  18:06:05  matt
  168.  * When player types space in callsign, comes up as underscore
  169.  * 
  170.  * Revision 1.91  1994/11/30  12:28:22  adam
  171.  * added PCX support
  172.  * 
  173.  * Revision 1.90  1994/11/30  12:10:59  adam
  174.  * added support for PCX titles/brief screens
  175.  * 
  176.  * Revision 1.89  1994/11/29  00:59:12  allender
  177.  * change newmenu_get_filename so demo files can be deleted too
  178.  * 
  179.  * Revision 1.88  1994/11/27  21:16:18  allender
  180.  * made some return values in newmenu_get_filename 0 instead of -1
  181.  * 
  182.  * Revision 1.87  1994/11/27  16:58:17  matt
  183.  * Made printscreen work all the time (not just when no ndebug) and made it
  184.  * work when getting a filename.
  185.  * 
  186.  * Revision 1.86  1994/11/27  16:47:51  john
  187.  * Made the call to fade in palette only happen if it needs to be, just
  188.  * because I thought it might reduce code paging with vm in menus.
  189.  * 
  190.  * Revision 1.85  1994/11/26  15:30:16  matt
  191.  * Allow escape out of change pilot menu
  192.  * 
  193.  * Revision 1.84  1994/11/26  14:17:26  matt
  194.  * Player can now only enter valid chars for his name
  195.  * 
  196.  * Revision 1.83  1994/11/23  14:13:17  allender
  197.  * if no demo files, displays less "techy" message
  198.  * 
  199.  * Revision 1.82  1994/11/21  11:55:52  john
  200.  * Fixed some sound pausing in menus bugs.
  201.  * 
  202.  * Revision 1.81  1994/11/19  15:14:58  mike
  203.  * remove unused code and data
  204.  * 
  205.  * Revision 1.80  1994/11/18  23:37:54  john
  206.  * Changed some shorts to ints.
  207.  * 
  208.  * Revision 1.79  1994/11/15  09:29:21  john
  209.  * Made it so that pressing a letter when selecting players moves to 
  210.  * a matching choice.
  211.  * 
  212.  * Revision 1.78  1994/11/14  17:12:28  adam
  213.  * *** empty log message ***
  214.  * 
  215.  * Revision 1.77  1994/11/14  16:58:31  rob
  216.  * Tried to fix a problem with save demo dialog.
  217.  * 
  218.  * Revision 1.76  1994/11/14  16:13:46  matt
  219.  * Fixed handling of players with DOS device names
  220.  * 
  221.  * Revision 1.75  1994/11/13  18:12:53  matt
  222.  * Fixed handling of filenames that are the same as DOS devices
  223.  * 
  224.  * Revision 1.74  1994/11/13  17:20:44  john
  225.  * Fixed text a bit.
  226.  * 
  227.  * Revision 1.73  1994/11/13  17:18:22  john
  228.  * Changed wording of new pilot.
  229.  * 
  230.  * Revision 1.72  1994/11/13  17:14:21  john
  231.  * Fixed bug with player list box.
  232.  * 
  233.  * Revision 1.71  1994/11/13  17:12:48  john
  234.  * Fixed broken demo file list.
  235.  * 
  236.  * Revision 1.70  1994/11/13  17:04:49  john
  237.  * Made the callsign entry be a list box and gave the ability
  238.  * to delete players.
  239.  * 
  240.  * Revision 1.69  1994/11/13  15:38:03  john
  241.  * Added critical error handler to game.  Took out -editor command line
  242.  * option because it didn't work anymore and wasn't worth fixing.  Made scores
  243.  * not use MINER enviroment variable on release version, and made scores
  244.  * not print an error if there is no descent.hi.
  245.  * 
  246.  * Revision 1.68  1994/11/11  18:17:03  rob
  247.  * Made multi_menu_poll return a value to exit menus.
  248.  * 
  249.  * Revision 1.67  1994/11/11  11:07:06  rob
  250.  * Added include of multi.h
  251.  * 
  252.  * Revision 1.66  1994/11/10  20:25:16  rob
  253.  * John's stuff to make network menus work.
  254.  * 
  255.  * Revision 1.65  1994/11/08  14:51:39  john
  256.  * Added nm_messagebox1, (like the original, only you can pass a function).
  257.  * 
  258.  * Revision 1.64  1994/11/08  08:30:39  john
  259.  * Fixed bug with centering titles.
  260.  * 
  261.  * Revision 1.63  1994/11/08  08:27:00  john
  262.  * Made titles and subtitles center.
  263.  * 
  264.  * Revision 1.62  1994/11/07  09:40:48  john
  265.  * Neatend file list box some.
  266.  * 
  267.  * Revision 1.61  1994/11/05  17:22:41  john
  268.  * Fixed lots of sequencing problems with newdemo stuff.
  269.  * 
  270.  * Revision 1.60  1994/11/05  15:04:08  john
  271.  * Added non-popup menu for the main menu, so that scores and credits don't have to save
  272.  * the background.
  273.  * 
  274.  * Revision 1.59  1994/11/05  14:03:52  john
  275.  * Fixed fade transitions between all screens by making gr_palette_fade_in and out keep
  276.  * track of whether the palette is faded in or not.  Then, wherever the code needs to fade out,
  277.  * it just calls gr_palette_fade_out and it will fade out if it isn't already.  The same with fade_in.
  278.  * This eliminates the need for all the flags like Menu_fade_out, game_fade_in palette, etc.
  279.  * 
  280.  * Revision 1.58  1994/11/04  20:11:50  john
  281.  * Neatening up palette stuff with demos.
  282.  * 
  283.  * Revision 1.57  1994/11/04  13:49:24  allender
  284.  * fixed newmenu_get_filename to work with less than 10 files
  285.  * 
  286.  * Revision 1.56  1994/11/03  19:37:44  john
  287.  * Added scrolling file list box
  288.  * 
  289.  * Revision 1.55  1994/10/31  18:16:42  john
  290.  * Made Pad arrows work with menus.
  291.  * 
  292.  * Revision 1.54  1994/10/28  14:54:25  john
  293.  * Added forward dec. for newmenu_close.
  294.  * .\
  295.  * 
  296.  * Revision 1.53  1994/10/28  14:53:00  john
  297.  * Fixed hideous bug that would bomb if you called newmenu_draw_background
  298.  * before any menus were ever displayed.
  299.  * 
  300.  * Revision 1.52  1994/10/24  19:56:53  john
  301.  * Made the new user setup prompt for config options.
  302.  * 
  303.  * Revision 1.51  1994/10/24  15:15:49  john
  304.  * Made Esc exit nm_messagebox's,
  305.  * ,
  306.  * 
  307.  * Revision 1.50  1994/10/21  15:20:20  john
  308.  * Made PrtScr do screen dump, not F2.
  309.  * 
  310.  * Revision 1.49  1994/10/18  12:33:38  john
  311.  * Only used copy the item text into the saved_text field
  312.  * if it is an inputbox or inputbox_menu.
  313.  * 
  314.  * Revision 1.48  1994/10/17  11:04:01  john
  315.  * Made backtab work also.
  316.  * 
  317.  * Revision 1.47  1994/10/17  10:47:49  john
  318.  * MAde Tab work like down arrow.
  319.  * 
  320.  * Revision 1.46  1994/10/17  10:45:10  john
  321.  * Made the player able to abort death by pressing any button or key.
  322.  * 
  323.  * Revision 1.45  1994/10/13  21:52:02  john
  324.  * Made it so that if a messagebox has 1 choice, then
  325.  * Esc will return -1.
  326.  * 
  327.  * Revision 1.44  1994/10/13  11:35:38  john
  328.  * Made Thrustmaster FCS Hat work.  Put a background behind the
  329.  * keyboard configure.  Took out turn_sensitivity.  Changed sound/config
  330.  * menu to new menu. Made F6 be calibrate joystick.
  331.  * 
  332.  * Revision 1.43  1994/10/11  17:18:52  john
  333.  * Fixed bug with sliders always starting at -1.
  334.  * 
  335.  * Revision 1.42  1994/10/11  17:08:29  john
  336.  * Added sliders for volume controls.
  337.  * 
  338.  * Revision 1.41  1994/10/06  16:04:40  john
  339.  * Made text items color differently than others. Adam
  340.  * is gonna make a diff colored font for these.
  341.  * 
  342.  * Revision 1.40  1994/10/06  15:08:23  rob
  343.  * Allowed any negative key value to abort the menu and return.
  344.  * 
  345.  * Revision 1.39  1994/10/04  10:26:06  matt
  346.  * Changed fade in to happen every time a global var is set
  347.  * 
  348.  * Revision 1.38  1994/10/04  09:16:08  john
  349.  * If you pass -1 as choice in newmenu_do1, then
  350.  * no item is highlighted until you press up or
  351.  * down arrows.
  352.  * 
  353.  * Revision 1.37  1994/10/03  23:44:37  matt
  354.  * Save & restore palette effect around menus & pause message
  355.  * 
  356.  * Revision 1.36  1994/10/03  22:59:40  matt
  357.  * Re-enabled backspace to generate Int3()
  358.  * 
  359.  * Revision 1.35  1994/10/03  19:11:21  matt
  360.  * Changed string input cursor to blinking underscore
  361.  * 
  362.  * Revision 1.34  1994/10/03  14:44:15  john
  363.  * Added newmenu_do1, which allows you to pass the starting
  364.  * item to the menu system
  365.  * 
  366.  * Revision 1.33  1994/09/30  11:51:21  john
  367.  * Added Matt's NM_TYPE_INPUT_MENU
  368.  * 
  369.  * Revision 1.32  1994/09/28  17:22:56  matt
  370.  * Added extra space between subtitle and menu items
  371.  * Made shortcut key check ignore leading spaces in text
  372.  * 
  373.  * Revision 1.31  1994/09/15  16:11:22  john
  374.  * Added support for VFX1 head tracking. Fixed bug with memory over-
  375.  * write when using stereo mode.
  376.  * 
  377.  * Revision 1.30  1994/09/12  09:52:59  john
  378.  * Made global flush function that flushes keyboard,mouse, and joystick.
  379.  * 
  380.  * Revision 1.29  1994/09/10  19:10:54  matt
  381.  * Fixed a few things (like arrow key handling) for menus with all
  382.  * text items, such as the key help message.
  383.  * 
  384.  * Revision 1.28  1994/09/01  18:55:38  john
  385.  * freed scores.lbm
  386.  * 
  387.  * Revision 1.27  1994/09/01  18:03:50  john
  388.  * Neatened up scores a bit.
  389.  * 
  390.  * Revision 1.26  1994/08/30  20:38:13  john
  391.  * Passed citem in newmenu sub.
  392.  * 
  393.  * Revision 1.25  1994/08/30  11:13:01  john
  394.  * Added beveled edges to menus.
  395.  * 
  396.  * Revision 1.24  1994/08/26  13:01:58  john
  397.  * Put high score system in.
  398.  * 
  399.  * Revision 1.23  1994/08/16  00:18:44  john
  400.  * Made pressing the first letter of a menu
  401.  * item move to it.
  402.  * 
  403.  * Revision 1.22  1994/08/15  23:17:43  john
  404.  * *** empty log message ***
  405.  * 
  406.  * Revision 1.21  1994/08/15  23:15:28  john
  407.  * Made 1 menu/checkbox return with any keypress.
  408.  * 
  409.  * Revision 1.20  1994/08/12  10:18:23  john
  410.  * *** empty log message ***
  411.  * 
  412.  * Revision 1.19  1994/08/12  10:09:11  john
  413.  * Made borders better.
  414.  * 
  415.  * Revision 1.18  1994/08/12  03:11:16  john
  416.  * Made network be default off; Moved network options into
  417.  * main menu.  Made starting net game check that mines are the
  418.  * same.
  419.  * 
  420.  * Revision 1.17  1994/08/11  22:14:43  john
  421.  * Free'd up some memory that I forgot to free.
  422.  * 
  423.  * Revision 1.16  1994/08/11  19:27:35  john
  424.  * Made the Backspace drop into the debugger only
  425.  * if you're not in an inputbox.
  426.  * 
  427.  * Revision 1.15  1994/08/11  18:01:49  matt
  428.  * Added F2 and BACKSPACE keys to new menu system
  429.  * 
  430.  * Revision 1.14  1994/08/11  14:25:58  john
  431.  * *** empty log message ***
  432.  * 
  433.  * Revision 1.13  1994/08/11  14:25:40  john
  434.  * *** empty log message ***
  435.  * 
  436.  * Revision 1.12  1994/08/11  13:47:02  john
  437.  * Made newmenu have subtitles, passed key through to
  438.  * the newmenu subfunctions.
  439.  * 
  440.  * Revision 1.11  1994/08/11  12:45:08  john
  441.  * *** empty log message ***
  442.  * 
  443.  * Revision 1.10  1994/08/11  12:25:45  john
  444.  * Made right_offset spacing different
  445.  * 
  446.  * Revision 1.9  1994/08/11  12:09:49  john
  447.  * Made work with bitmapped fonts.
  448.  * 
  449.  * Revision 1.8  1994/08/10  19:56:16  john
  450.  * Changed font stuff; Took out old menu; messed up lots of
  451.  * other stuff like game sequencing messages, etc.
  452.  * 
  453.  * Revision 1.7  1994/07/27  16:12:23  john
  454.  * Changed newmenu system to have a callback function.
  455.  * /.
  456.  * 
  457.  * Revision 1.6  1994/07/25  15:10:23  john
  458.  * *** empty log message ***
  459.  * 
  460.  * Revision 1.5  1994/07/25  12:33:35  john
  461.  * Network "pinging" in.
  462.  * 
  463.  * Revision 1.4  1994/07/24  18:21:27  john
  464.  * Took out first time stuff.
  465.  * 
  466.  * Revision 1.3  1994/07/24  17:32:47  john
  467.  * Added percent item.  Also neatend up a bit.
  468.  * 
  469.  * Revision 1.2  1994/07/22  17:48:13  john
  470.  * Added new menuing system.
  471.  * 
  472.  * Revision 1.1  1994/07/22  13:55:38  john
  473.  * Initial revision
  474.  * 
  475.  * 
  476.  */
  477.  
  478.  
  479. #pragma off (unreferenced)
  480. static char rcsid[] = "$Id: newmenu.c 2.8 1995/05/26 16:16:28 john Exp $";
  481. #pragma on (unreferenced)
  482.  
  483. #include <stdio.h>
  484. #include <stdlib.h>
  485. #include <string.h>
  486. #include <dos.h>
  487. #include <stdarg.h>
  488. #include <ctype.h>
  489. #include <io.h>
  490.  
  491. #include "error.h"
  492. #include "types.h"
  493. #include "gr.h"
  494. #include "mono.h"
  495. #include "key.h"
  496. #include "palette.h"
  497. #include "game.h"
  498. #include "text.h"
  499.  
  500. #include "newmenu.h"
  501. #include "gamefont.h"
  502. #include "network.h"
  503. #include "iff.h"
  504. #include "pcx.h"
  505. #include "mem.h"
  506. #include "mouse.h"
  507. #include "joy.h"
  508. #include "digi.h"
  509.  
  510. #include "multi.h"
  511. #include "endlevel.h"
  512. #include "screens.h"
  513. #include "vfx.h"
  514. #include "kconfig.h"
  515. #include "player.h"
  516.  
  517. #define TITLE_FONT          (Gamefonts[GFONT_BIG_1])
  518.  
  519. #define SUBTITLE_FONT    (Gamefonts[GFONT_MEDIUM_3])
  520. #define CURRENT_FONT      (Gamefonts[GFONT_MEDIUM_2])
  521. #define NORMAL_FONT      (Gamefonts[GFONT_MEDIUM_1])
  522. #define TEXT_FONT          (Gamefonts[GFONT_MEDIUM_3])
  523.  
  524. #define NORMAL_CHECK_BOX    ""
  525. #define CHECKED_CHECK_BOX    "‚"
  526. #define NORMAL_RADIO_BOX    ""
  527. #define CHECKED_RADIO_BOX    "€"
  528. #define CURSOR_STRING        "_"
  529. #define SLIDER_LEFT            "ƒ"        // 131
  530. #define SLIDER_RIGHT            "„"        // 132
  531. #define SLIDER_MIDDLE        "…"        // 133
  532. #define SLIDER_MARKER        "†"        // 134
  533.  
  534. int Newmenu_first_time = 1;
  535. //--unused-- int Newmenu_fade_in = 1;
  536.  
  537. typedef struct bkg {
  538.     grs_canvas * menu_canvas;
  539.     grs_bitmap * saved;            // The background under the menu.
  540.     grs_bitmap * background;
  541. } bkg;
  542.  
  543. grs_bitmap nm_background;
  544.  
  545. #define MESSAGEBOX_TEXT_SIZE 300        // How many characters in messagebox
  546. #define MAX_TEXT_WIDTH     200                // How many pixels wide a input box can be
  547.  
  548. extern void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest);
  549.  
  550. void newmenu_close()    {
  551.     if ( nm_background.bm_data )
  552.         free(nm_background.bm_data);
  553.     Newmenu_first_time = 1;
  554. }
  555.  
  556. void nm_draw_background1(char * filename)
  557. {
  558.     int pcx_error;
  559.     grs_bitmap *bmp;
  560.     int x, y;
  561.  
  562.     gr_clear_canvas( BM_XRGB(0,0,0) );
  563.     x = (grd_curcanv->cv_bitmap.bm_w - 320) / 2;
  564.     y = (grd_curcanv->cv_bitmap.bm_h - 200) / 2;
  565.     bmp = gr_create_sub_bitmap( &grd_curcanv->cv_bitmap, x, y, 320, 200 );
  566.     pcx_error = pcx_read_bitmap(filename,bmp,bmp->bm_type,NULL);
  567.     Assert(pcx_error == PCX_ERROR_NONE);
  568.     
  569.     gr_free_sub_bitmap(bmp);
  570. }
  571.  
  572. void nm_draw_background(int x1, int y1, int x2, int y2 )
  573. {
  574.     int w,h;
  575.  
  576.     if (Newmenu_first_time)    {
  577.         int pcx_error;
  578.         ubyte newpal[768];
  579.         atexit( newmenu_close );
  580.         Newmenu_first_time = 0;
  581.  
  582.         nm_background.bm_data=NULL;        
  583.         pcx_error = pcx_read_bitmap("SCORES.PCX",&nm_background,BM_LINEAR,newpal);
  584.         Assert(pcx_error == PCX_ERROR_NONE);
  585.  
  586.         gr_remap_bitmap_good( &nm_background, newpal, -1, -1 );
  587.     }
  588.  
  589.     if ( x1 < 0 ) x1 = 0;
  590.     if ( y1 < 0 ) y1 = 0;
  591.  
  592.     w = x2-x1+1;
  593.     h = y2-y1+1;
  594.  
  595.     if ( w > nm_background.bm_w ) w = nm_background.bm_w;
  596.     if ( h > nm_background.bm_h ) h = nm_background.bm_h;
  597.     
  598.     x2 = x1 + w - 1;
  599.     y2 = y1 + h - 1;
  600.  
  601.     gr_bm_bitblt(w, h, x1, y1, 0, 0, &nm_background, &(grd_curcanv->cv_bitmap) );
  602.  
  603.     Gr_scanline_darkening_level = 2*7;
  604.  
  605.     gr_setcolor( BM_XRGB(0,0,0) );
  606.     gr_urect( x2-5, y1+5, x2-5, y2-5 );
  607.     gr_urect( x2-4, y1+4, x2-4, y2-5 );
  608.     gr_urect( x2-3, y1+3, x2-3, y2-5 );
  609.     gr_urect( x2-2, y1+2, x2-2, y2-5 );
  610.     gr_urect( x2-1, y1+1, x2-1, y2-5 );
  611.     gr_urect( x2+0, y1+0, x2-0, y2-5 );
  612.  
  613.     gr_urect( x1+5, y2-5, x2, y2-5 );
  614.     gr_urect( x1+4, y2-4, x2, y2-4 );
  615.     gr_urect( x1+3, y2-3, x2, y2-3 );
  616.     gr_urect( x1+2, y2-2, x2, y2-2 );
  617.     gr_urect( x1+1, y2-1, x2, y2-1 );
  618.     gr_urect( x1+0, y2, x2, y2-0 );
  619.  
  620.     Gr_scanline_darkening_level = GR_FADE_LEVELS;
  621. }
  622.  
  623. void nm_restore_background( int x, int y, int w, int h )
  624. {
  625.     int x1, x2, y1, y2;
  626.  
  627.     x1 = x; x2 = x+w-1;
  628.     y1 = y; y2 = y+h-1;
  629.  
  630.     if ( x1 < 0 ) x1 = 0;
  631.     if ( y1 < 0 ) y1 = 0;
  632.  
  633.     if ( x2 >= nm_background.bm_w ) x2=nm_background.bm_w-1;
  634.     if ( y2 >= nm_background.bm_h ) y2=nm_background.bm_h-1;
  635.  
  636.     w = x2 - x1 + 1;
  637.     h = y2 - y1 + 1;
  638.  
  639.     gr_bm_bitblt(w, h, x1, y1, x1, y1, &nm_background, &(grd_curcanv->cv_bitmap) );
  640. }
  641.  
  642. // Draw a left justfied string
  643. void nm_string( bkg * b, int w1,int x, int y, char * s )
  644. {
  645.     int w,h,aw;
  646.     char *p,*s1;
  647.  
  648.     p = strchr( s, '\t' );
  649.     if (p && (w1>0) )    {
  650.         *p = '\0';
  651.         s1 = p+1;
  652.     }
  653.  
  654.     gr_get_string_size(s, &w, &h, &aw  );
  655.  
  656.     if (w1 > 0)
  657.         w = w1;
  658.  
  659.     // CHANGED
  660.     gr_bm_bitblt(b->background->bm_w-15, h, 5, y, 5, y, b->background, &(grd_curcanv->cv_bitmap) );
  661.     //gr_bm_bitblt(w, h, x, y, x, y, b->background, &(grd_curcanv->cv_bitmap) );
  662.     
  663.     gr_string( x, y, s );
  664.  
  665.     if (p && (w1>0) )    {
  666.         gr_get_string_size(s1, &w, &h, &aw  );
  667.  
  668.         gr_string( x+w1-w, y, s1 );
  669.  
  670.         *p = '\t';
  671.     }
  672.  
  673. }
  674.  
  675.  
  676. // Draw a slider and it's string
  677. void nm_string_slider( bkg * b, int w1,int x, int y, char * s )
  678. {
  679.     int w,h,aw;
  680.     char *p,*s1;
  681.  
  682.     p = strchr( s, '\t' );
  683.     if (p)    {
  684.         *p = '\0';
  685.         s1 = p+1;
  686.     }
  687.  
  688.     gr_get_string_size(s, &w, &h, &aw  );
  689.     // CHANGED
  690.     gr_bm_bitblt(b->background->bm_w-15, h, 5, y, 5, y, b->background, &(grd_curcanv->cv_bitmap) );
  691.     //gr_bm_bitblt(w, h, x, y, x, y, b->background, &(grd_curcanv->cv_bitmap) );
  692.  
  693.     gr_string( x, y, s );
  694.  
  695.     if (p)    {
  696.         gr_get_string_size(s1, &w, &h, &aw  );
  697.  
  698.         // CHANGED
  699.         gr_bm_bitblt(w, 1, x+w1-w, y, x+w1-w, y, b->background, &(grd_curcanv->cv_bitmap) );
  700.         // CHANGED
  701.         gr_bm_bitblt(w, 1, x+w1-w, y+h-1, x+w1-w, y, b->background, &(grd_curcanv->cv_bitmap) );
  702.  
  703.         gr_string( x+w1-w, y, s1 );
  704.  
  705.         *p = '\t';
  706.     }
  707.  
  708. }
  709.  
  710.  
  711. // Draw a left justfied string with black background.
  712. void nm_string_black( bkg * b, int w1,int x, int y, char * s )
  713. {
  714.     int w,h,aw;
  715.     gr_get_string_size(s, &w, &h, &aw  );
  716.     b = b;                    
  717.     if (w1 == 0) w1 = w;
  718.  
  719.     gr_setcolor( BM_XRGB(0,0,0) );
  720.     gr_rect( x, y, x+w1-1, y+h-1 );
  721.     
  722.     gr_string( x, y, s );
  723. }
  724.  
  725.  
  726. // Draw a right justfied string
  727. void nm_rstring( bkg * b,int w1,int x, int y, char * s )
  728. {
  729.     int w,h,aw;
  730.     gr_get_string_size(s, &w, &h, &aw  );
  731.     x -= 3;
  732.  
  733.     if (w1 == 0) w1 = w;
  734.  
  735.     //mprintf( 0, "Width = %d, string='%s'\n", w, s );
  736.  
  737.     // CHANGED
  738.     gr_bm_bitblt(w1, h, x-w1, y, x-w1, y, b->background, &(grd_curcanv->cv_bitmap) );
  739.     
  740.     gr_string( x-w, y, s );
  741. }
  742.  
  743. #include "timer.h"
  744.  
  745. //for text items, constantly redraw cursor (to achieve flash)
  746. update_cursor( newmenu_item *item)
  747. {
  748.     int w,h,aw;
  749.     fix time = timer_get_approx_seconds();
  750.     int x,y;
  751.     char * text = item->text;
  752.  
  753.     Assert(item->type==NM_TYPE_INPUT_MENU || item->type==NM_TYPE_INPUT);
  754.  
  755.     while( *text )    {
  756.         gr_get_string_size(text, &w, &h, &aw  );
  757.         if ( w > item->w-10 )
  758.             text++;
  759.         else
  760.             break;
  761.     }
  762.     if (*text==0) 
  763.         w = 0;
  764.     x = item->x+w; y = item->y;
  765.  
  766.     if (time & 0x8000)
  767.         gr_string( x, y, CURSOR_STRING );
  768.     else {
  769.         gr_setcolor( BM_XRGB(0,0,0) );
  770.         gr_rect( x, y, x+grd_curcanv->cv_font->ft_w-1, y+grd_curcanv->cv_font->ft_h-1 );
  771.     }
  772.  
  773. }
  774.  
  775. void nm_string_inputbox( bkg *b, int w, int x, int y, char * text, int current )
  776. {
  777.     int w1,h1,aw;
  778.  
  779.     while( *text )    {
  780.         gr_get_string_size(text, &w1, &h1, &aw  );
  781.         if ( w1 > w-10 )
  782.             text++;
  783.         else
  784.             break;
  785.     }
  786.     if ( *text == 0 )
  787.         w1 = 0;
  788.     nm_string_black( b, w, x, y, text );
  789.  
  790.     if ( current )    {
  791.         gr_string( x+w1, y, CURSOR_STRING );
  792.     }
  793. }
  794.  
  795. void draw_item( bkg * b, newmenu_item *item, int is_current )
  796. {
  797.     if (is_current)
  798.         grd_curcanv->cv_font = CURRENT_FONT;
  799.     else
  800.         grd_curcanv->cv_font = NORMAL_FONT;
  801.     
  802.     switch( item->type )    {
  803.     case NM_TYPE_TEXT:
  804.         grd_curcanv->cv_font=TEXT_FONT;
  805.         // fall through on purpose
  806.     case NM_TYPE_MENU:
  807.         nm_string( b, item->w, item->x, item->y, item->text );
  808.         break;
  809.     case NM_TYPE_SLIDER:    {
  810.         int j;
  811.         if (item->value < item->min_value) item->value=item->min_value;
  812.         if (item->value > item->max_value) item->value=item->max_value;
  813.         sprintf( item->saved_text, "%s\t%s", item->text, SLIDER_LEFT );
  814.         for (j=0; j<(item->max_value-item->min_value+1); j++ )    {
  815.             sprintf( item->saved_text, "%s%s", item->saved_text,SLIDER_MIDDLE );
  816.         }
  817.         sprintf( item->saved_text, "%s%s", item->saved_text,SLIDER_RIGHT );
  818.         
  819.         item->saved_text[item->value+1+strlen(item->text)+1] = SLIDER_MARKER[0];
  820.         
  821.         nm_string_slider( b, item->w, item->x, item->y, item->saved_text );
  822.         }
  823.         break;
  824.     case NM_TYPE_INPUT_MENU:
  825.         if ( item->group==0 )        {
  826.             nm_string( b, item->w, item->x, item->y, item->text );
  827.         } else {
  828.             nm_string_inputbox( b, item->w, item->x, item->y, item->text, is_current );
  829.         }
  830.         break;
  831.     case NM_TYPE_INPUT:
  832.         nm_string_inputbox( b, item->w, item->x, item->y, item->text, is_current );
  833.         break;
  834.     case NM_TYPE_CHECK:
  835.         nm_string( b, item->w, item->x, item->y, item->text );
  836.         if (item->value)
  837.             nm_rstring( b,item->right_offset,item->x, item->y, CHECKED_CHECK_BOX );
  838.         else                                                          
  839.             nm_rstring( b,item->right_offset,item->x, item->y, NORMAL_CHECK_BOX );
  840.         break;
  841.     case NM_TYPE_RADIO:
  842.         nm_string( b, item->w, item->x, item->y, item->text );
  843.         if (item->value)
  844.             nm_rstring( b,item->right_offset, item->x, item->y, CHECKED_RADIO_BOX );
  845.         else
  846.             nm_rstring( b,item->right_offset, item->x, item->y, NORMAL_RADIO_BOX );
  847.         break;
  848.     case NM_TYPE_NUMBER:    {
  849.         char text[10];
  850.         if (item->value < item->min_value) item->value=item->min_value;
  851.         if (item->value > item->max_value) item->value=item->max_value;
  852.         nm_string( b, item->w, item->x, item->y, item->text );
  853.         sprintf( text, "%d", item->value );
  854.         nm_rstring( b,item->right_offset,item->x, item->y, text );
  855.         }
  856.         break;
  857.     }
  858.  
  859. }
  860.  
  861. char *Newmenu_allowed_chars=NULL;
  862.  
  863. //returns true if char is allowed
  864. char_allowed(char c)
  865. {
  866.     char *p = Newmenu_allowed_chars;
  867.  
  868.     if (!p)
  869.         return 1;
  870.  
  871.     while (*p) {
  872.         Assert(p[1]);
  873.  
  874.         if (c>=p[0] && c<=p[1])
  875.             return 1;
  876.  
  877.         p += 2;
  878.     }
  879.  
  880.     return 0;
  881. }
  882.  
  883. void strip_end_whitespace( char * text )
  884. {
  885.     int i,l;
  886.     l = strlen( text );
  887.     for (i=l-1; i>=0; i-- )    {
  888.         if ( isspace(text[i]) )
  889.             text[i] = 0;
  890.         else
  891.             return;
  892.     }
  893. }
  894.  
  895. int newmenu_do( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem) )
  896. {
  897.     return newmenu_do3( title, subtitle, nitems, item, subfunction, 0, NULL, -1, -1 );
  898. }
  899.  
  900. int newmenu_do1( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem )
  901. {
  902.     return newmenu_do3( title, subtitle, nitems, item, subfunction, citem, NULL, -1, -1 );
  903. }
  904.  
  905.  
  906. int newmenu_do2( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename )
  907. {
  908.     return newmenu_do3( title, subtitle, nitems, item, subfunction, citem, filename, -1, -1 );
  909. }
  910.  
  911. int newmenu_do3( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename, int width, int height )
  912. {
  913.     int old_keyd_repeat, done;
  914.     int  choice,old_choice,i,j,x,y,w,h,aw, tw, th, twidth,fm,right_offset;
  915.     int k, nmenus, nothers;
  916.     grs_canvas * save_canvas;
  917.     grs_font * save_font;
  918.     int string_width, string_height, average_width;
  919.     int ty;
  920.     bkg bg;
  921.     int all_text=0;        //set true if all text items
  922.     int time_stopped=0;
  923.  
  924.     if (nitems < 1 )
  925.         return -1;
  926.  
  927.     set_screen_mode(SCREEN_MENU);
  928.  
  929. //NO_SOUND_PAUSE    if ( Function_mode == FMODE_GAME )    {
  930. //NO_SOUND_PAUSE        digi_pause_all();
  931. //NO_SOUND_PAUSE        sound_stopped = 1;
  932. //NO_SOUND_PAUSE    }
  933.  
  934.     if (!((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME) && (!Endlevel_sequence)) )
  935.     {
  936.         time_stopped = 1;
  937.         stop_time();
  938.     }
  939.  
  940.     save_canvas = grd_curcanv;
  941.     gr_set_current_canvas( NULL );            
  942.     save_font = grd_curcanv->cv_font;
  943.  
  944.     tw = th = 0;
  945.  
  946.     if ( title )    {
  947.         grd_curcanv->cv_font = TITLE_FONT;
  948.         gr_get_string_size(title,&string_width,&string_height,&average_width );
  949.         tw = string_width;
  950.         th = string_height;
  951.     }
  952.     if ( subtitle )    {
  953.         grd_curcanv->cv_font = SUBTITLE_FONT;
  954.         gr_get_string_size(subtitle,&string_width,&string_height,&average_width );
  955.         if (string_width > tw )
  956.             tw = string_width;
  957.         th += string_height;
  958.     }
  959.  
  960.     th += 8;        //put some space between titles & body
  961.  
  962.     grd_curcanv->cv_font = NORMAL_FONT;
  963.  
  964.     w = aw = 0;
  965.     h = th;
  966.     nmenus = nothers = 0;
  967.  
  968.     // Find menu height & width (store in w,h)
  969.     for (i=0; i<nitems; i++ )    {
  970.         item[i].redraw=1;
  971.         item[i].y = h;
  972.         gr_get_string_size(item[i].text,&string_width,&string_height,&average_width );
  973.         item[i].right_offset = 0;
  974.  
  975.         item[i].saved_text[0] = '\0';
  976.  
  977.         if ( item[i].type == NM_TYPE_SLIDER )    {
  978.             int w1,h1,aw1;
  979.             nothers++;
  980.             sprintf( item[i].saved_text, "%s", SLIDER_LEFT );
  981.             for (j=0; j<(item[i].max_value-item[i].min_value+1); j++ )    {
  982.                 sprintf( item[i].saved_text, "%s%s", item[i].saved_text,SLIDER_MIDDLE );
  983.             }
  984.             sprintf( item[i].saved_text, "%s%s", item[i].saved_text,SLIDER_RIGHT );
  985.             gr_get_string_size(item[i].saved_text,&w1,&h1,&aw1 );
  986.             string_width += w1 + aw;
  987.         }
  988.  
  989.         if ( item[i].type == NM_TYPE_MENU )    {
  990.             nmenus++;
  991.         }
  992.  
  993.         if ( item[i].type == NM_TYPE_CHECK )    {
  994.             int w1,h1,aw1;
  995.             nothers++;
  996.             gr_get_string_size(NORMAL_CHECK_BOX, &w1, &h1, &aw1  );
  997.             item[i].right_offset = w1;
  998.             gr_get_string_size(CHECKED_CHECK_BOX, &w1, &h1, &aw1  );
  999.             if (w1 > item[i].right_offset)
  1000.                 item[i].right_offset = w1;
  1001.         }
  1002.         
  1003.         if (item[i].type == NM_TYPE_RADIO ) {
  1004.             int w1,h1,aw1;
  1005.             nothers++;
  1006.             gr_get_string_size(NORMAL_RADIO_BOX, &w1, &h1, &aw1  );
  1007.             item[i].right_offset = w1;
  1008.             gr_get_string_size(CHECKED_RADIO_BOX, &w1, &h1, &aw1  );
  1009.             if (w1 > item[i].right_offset)
  1010.                 item[i].right_offset = w1;
  1011.         }
  1012.  
  1013.         if  (item[i].type==NM_TYPE_NUMBER )    {
  1014.             int w1,h1,aw1;
  1015.             char test_text[20];
  1016.             nothers++;
  1017.             sprintf( test_text, "%d", item[i].max_value );
  1018.             gr_get_string_size( test_text, &w1, &h1, &aw1 );
  1019.             item[i].right_offset = w1;
  1020.             sprintf( test_text, "%d", item[i].min_value );
  1021.             gr_get_string_size( test_text, &w1, &h1, &aw1 );
  1022.             if ( w1 > item[i].right_offset)
  1023.                 item[i].right_offset = w1;
  1024.         }
  1025.  
  1026.         if ( item[i].type == NM_TYPE_INPUT )    {
  1027.             Assert( strlen(item[i].text) < NM_MAX_TEXT_LEN );
  1028.             strcpy(item[i].saved_text, item[i].text );
  1029.             nothers++;
  1030.             string_width = item[i].text_len*grd_curcanv->cv_font->ft_w+item[i].text_len;
  1031.             if ( string_width > MAX_TEXT_WIDTH ) 
  1032.                 string_width = MAX_TEXT_WIDTH;
  1033.             item[i].value = -1;
  1034.         }
  1035.  
  1036.         if ( item[i].type == NM_TYPE_INPUT_MENU )    {
  1037.             Assert( strlen(item[i].text) < NM_MAX_TEXT_LEN );
  1038.             strcpy(item[i].saved_text, item[i].text );
  1039.             nmenus++;
  1040.             string_width = item[i].text_len*grd_curcanv->cv_font->ft_w+item[i].text_len;
  1041.             item[i].value = -1;
  1042.             item[i].group = 0;
  1043.         }
  1044.  
  1045.         item[i].w = string_width;
  1046.         item[i].h = string_height;
  1047.  
  1048.         if ( string_width > w )
  1049.             w = string_width;        // Save maximum width
  1050.         if ( average_width > aw )
  1051.             aw = average_width;
  1052.         h += string_height+1;        // Find the height of all strings
  1053.     }
  1054.  
  1055.     right_offset=0;
  1056.  
  1057.     if ( width > -1 )
  1058.         w = width;
  1059.  
  1060.     if ( height > -1 )
  1061.         h = height;
  1062.  
  1063.     for (i=0; i<nitems; i++ )    {
  1064.         item[i].w = w;
  1065.         if (item[i].right_offset > right_offset )
  1066.             right_offset = item[i].right_offset;
  1067.     }
  1068.     if (right_offset > 0 )
  1069.         right_offset += 3;
  1070.     
  1071.     //mprintf( 0, "Right offset = %d\n", right_offset );
  1072.  
  1073.     //gr_get_string_size("",&string_width,&string_height,&average_width );
  1074.  
  1075.     w += right_offset;
  1076.  
  1077.     twidth = 0;
  1078.     if ( tw > w )    {
  1079.         twidth = ( tw - w )/2;
  1080.         w = tw;
  1081.     }
  1082.             
  1083.     // Find min point of menu border
  1084. //    x = (grd_curscreen->sc_w-w)/2;
  1085. //    y = (grd_curscreen->sc_h-h)/2;
  1086.  
  1087.     w += 30;
  1088.     h += 30;
  1089.  
  1090.     if ( w > 320 ) w = 320;
  1091.     if ( h > 200 ) h = 200;
  1092.  
  1093.     x = (grd_curcanv->cv_bitmap.bm_w-w)/2;
  1094.     y = (grd_curcanv->cv_bitmap.bm_h-h)/2;
  1095.  
  1096.     if ( x < 0 ) x = 0;
  1097.     if ( y < 0 ) y = 0;
  1098.         
  1099.     if ( filename != NULL )    {
  1100.         nm_draw_background1( filename );
  1101.     }
  1102.  
  1103.     // Save the background of the display
  1104.     bg.menu_canvas = gr_create_sub_canvas( &grd_curscreen->sc_canvas, x, y, w, h );
  1105.     gr_set_current_canvas( bg.menu_canvas );
  1106.  
  1107.     if ( filename == NULL )    {
  1108.         // Save the background under the menu...
  1109.         bg.saved = gr_create_bitmap( w, h );
  1110.         Assert( bg.saved != NULL );
  1111.         gr_bm_bitblt(w, h, 0, 0, 0, 0, &grd_curcanv->cv_bitmap, bg.saved );
  1112.         gr_set_current_canvas( NULL );
  1113.         nm_draw_background(x,y,x+w-1,y+h-1);
  1114.         bg.background = gr_create_sub_bitmap(&nm_background,0,0,w,h);
  1115.         gr_set_current_canvas( bg.menu_canvas );
  1116.     } else {
  1117.         bg.saved = NULL;
  1118.         bg.background = gr_create_bitmap( w, h );
  1119.         Assert( bg.background != NULL );
  1120.         gr_bm_bitblt(w, h, 0, 0, 0, 0, &grd_curcanv->cv_bitmap, bg.background );
  1121.     }
  1122.  
  1123. // ty = 15 + (yborder/4);
  1124.  
  1125.     ty = 15;
  1126.  
  1127.     if ( title )    {
  1128.         grd_curcanv->cv_font = TITLE_FONT;
  1129.         gr_set_fontcolor( GR_GETCOLOR(31,31,31), -1 );
  1130.         gr_get_string_size(title,&string_width,&string_height,&average_width );
  1131.         tw = string_width;
  1132.         th = string_height;
  1133.         gr_printf( 0x8000, ty, title );
  1134.         ty += th;
  1135.     }
  1136.  
  1137.     if ( subtitle )    {
  1138.         grd_curcanv->cv_font = SUBTITLE_FONT;
  1139.         gr_set_fontcolor( GR_GETCOLOR(21,21,21), -1 );
  1140.         gr_get_string_size(subtitle,&string_width,&string_height,&average_width );
  1141.         tw = string_width;
  1142.         th = string_height;
  1143.         gr_printf( 0x8000, ty, subtitle );
  1144.         ty += th;
  1145.     }
  1146.  
  1147.     grd_curcanv->cv_font = NORMAL_FONT;
  1148.     
  1149.     // Update all item's x & y values.
  1150.     for (i=0; i<nitems; i++ )    {
  1151.         item[i].x = 15 + twidth + right_offset;
  1152.         item[i].y += 15;
  1153.         if ( item[i].type==NM_TYPE_RADIO )    {
  1154.             fm = -1;    // find first marked one
  1155.             for ( j=0; j<nitems; j++ )    {
  1156.                 if ( item[j].type==NM_TYPE_RADIO && item[j].group==item[i].group )    {
  1157.                     if (fm==-1 && item[j].value)
  1158.                         fm = j;
  1159.                     item[j].value = 0;
  1160.                 }
  1161.             }
  1162.             if ( fm>=0 )    
  1163.                 item[fm].value=1;
  1164.             else
  1165.                 item[i].value=1;
  1166.         }
  1167.     }
  1168.  
  1169.     old_keyd_repeat = keyd_repeat;
  1170.     keyd_repeat = 1;
  1171.  
  1172.     if (citem==-1)    {
  1173.         choice = -1;
  1174.     } else {
  1175.         if (citem < 0 ) citem = 0;
  1176.         if (citem > nitems-1 ) citem = nitems-1;
  1177.         choice = citem;
  1178.     
  1179.         while ( item[choice].type==NM_TYPE_TEXT )    {
  1180.             choice++;
  1181.             if (choice >= nitems ) {
  1182.                 choice=0; 
  1183.             }
  1184.             if (choice == citem ) {
  1185.                 choice=0; 
  1186.                 all_text=1;
  1187.                 break; 
  1188.             }
  1189.         }
  1190.     } 
  1191.     done = 0;
  1192.  
  1193.     // Clear mouse, joystick to clear button presses.
  1194.     game_flush_inputs();
  1195.  
  1196.     while(!done)    {
  1197.         //network_listen();
  1198.     
  1199.  
  1200.         k = key_inkey();
  1201.  
  1202.         if (subfunction)
  1203.             (*subfunction)(nitems,item,&k,choice);
  1204.  
  1205.         if (!time_stopped)    {
  1206.             // Save current menu box
  1207.             #ifdef NETWORK
  1208.             if (multi_menu_poll() == -1)
  1209.                 k = -2;
  1210.             #endif
  1211.         }
  1212.  
  1213.         if ( k<-1 ) {
  1214.             choice = k;
  1215.             k = -1;
  1216.             done = 1;
  1217.         }
  1218.                 
  1219.         switch (Config_control_type) {
  1220.         case    CONTROL_JOYSTICK:
  1221.         case    CONTROL_FLIGHTSTICK_PRO:
  1222.         case    CONTROL_THRUSTMASTER_FCS:
  1223.         case    CONTROL_GRAVIS_GAMEPAD:
  1224.             for (i=0; i<4; i++ )    
  1225.                  if (joy_get_button_down_cnt(i)>0) done=1;
  1226.             break;
  1227.         case    CONTROL_MOUSE:
  1228.         case    CONTROL_CYBERMAN:
  1229.             for (i=0; i<3; i++ )    
  1230.                 if (mouse_button_down_count(i)>0) done=1;
  1231.             break;
  1232.         }
  1233.     
  1234.  
  1235. //        if ( (nmenus<2) && (k>0) && (nothers==0) )
  1236. //            done=1;
  1237.  
  1238.         old_choice = choice;
  1239.     
  1240.         switch( k )    {
  1241.         case KEY_TAB + KEY_SHIFTED:
  1242.         case KEY_UP:
  1243.         case KEY_PAD8:
  1244.             if (all_text) break;
  1245.             do {
  1246.                 choice--;
  1247.                 if (choice >= nitems ) choice=0;
  1248.                 if (choice < 0 ) choice=nitems-1;
  1249.             } while ( item[choice].type==NM_TYPE_TEXT );
  1250.             if ((item[choice].type==NM_TYPE_INPUT) && (choice!=old_choice))    
  1251.                 item[choice].value = -1;
  1252.             if ((old_choice>-1) && (item[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=choice))    {
  1253.                 item[old_choice].group=0;
  1254.                 strcpy(item[old_choice].text, item[old_choice].saved_text );
  1255.                 item[old_choice].value = -1;
  1256.             }
  1257.             if (old_choice>-1) 
  1258.                 item[old_choice].redraw = 1;
  1259.             item[choice].redraw=1;
  1260.             break;
  1261.         case KEY_TAB:
  1262.         case KEY_DOWN:
  1263.         case KEY_PAD2:
  1264.             if (all_text) break;
  1265.             do {
  1266.                 choice++;
  1267.                 if (choice < 0 ) choice=nitems-1;
  1268.                 if (choice >= nitems ) choice=0;
  1269.             } while ( item[choice].type==NM_TYPE_TEXT );
  1270.             if ((item[choice].type==NM_TYPE_INPUT) && (choice!=old_choice))    
  1271.                 item[choice].value = -1;
  1272.             if ( (old_choice>-1) && (item[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=choice))    {
  1273.                 item[old_choice].group=0;
  1274.                 strcpy(item[old_choice].text, item[old_choice].saved_text );    
  1275.                 item[old_choice].value = -1;
  1276.             }
  1277.             if (old_choice>-1)
  1278.                 item[old_choice].redraw=1;
  1279.             item[choice].redraw=1;
  1280.             break;
  1281.         case KEY_SPACEBAR:
  1282.             if ( choice > -1 )    {
  1283.                 switch( item[choice].type )    {
  1284.                 case NM_TYPE_MENU:
  1285.                 case NM_TYPE_INPUT:
  1286.                 case NM_TYPE_INPUT_MENU:
  1287.                     break;
  1288.                 case NM_TYPE_CHECK:
  1289.                     if ( item[choice].value )
  1290.                         item[choice].value = 0;
  1291.                     else
  1292.                         item[choice].value = 1;
  1293.                     item[choice].redraw=1;
  1294.                     break;
  1295.                 case NM_TYPE_RADIO:
  1296.                     for (i=0; i<nitems; i++ )    {
  1297.                         if ((i!=choice) && (item[i].type==NM_TYPE_RADIO) && (item[i].group==item[choice].group) && (item[i].value) )    {
  1298.                             item[i].value = 0;
  1299.                             item[i].redraw = 1;
  1300.                         }
  1301.                     }
  1302.                     item[choice].value = 1;
  1303.                     item[choice].redraw = 1;
  1304.                     break;
  1305.                 }    
  1306.             }
  1307.             break;
  1308.  
  1309.         case KEY_ENTER:
  1310.         case KEY_PADENTER:
  1311.             if ( (choice>-1) && (item[choice].type==NM_TYPE_INPUT_MENU) && (item[choice].group==0))    {
  1312.                 item[choice].group = 1;
  1313.                 item[choice].redraw = 1;
  1314.                 if ( !strnicmp( item[choice].saved_text, TXT_EMPTY, strlen(TXT_EMPTY) ) )    {
  1315.                     item[choice].text[0] = 0;
  1316.                     item[choice].value = -1;
  1317.                 } else {    
  1318.                     strip_end_whitespace(item[choice].text);
  1319.                 }
  1320.             } else
  1321.                 done = 1;
  1322.             break;
  1323.  
  1324.         case KEY_ESC:
  1325.             if ( (choice>-1) && (item[choice].type==NM_TYPE_INPUT_MENU) && (item[choice].group==1))    {
  1326.                 item[choice].group=0;
  1327.                 strcpy(item[choice].text, item[choice].saved_text );    
  1328.                 item[choice].redraw=1;
  1329.                 item[choice].value = -1;
  1330.             } else {
  1331.                 done = 1;
  1332.                 choice = -1;
  1333.             }
  1334.             break;
  1335.  
  1336.         case KEY_PRINT_SCREEN:         save_screen_shot(0); break;
  1337.  
  1338.         #ifndef NDEBUG
  1339.         case KEY_BACKSP:    
  1340.             if ( (choice>-1) && (item[choice].type!=NM_TYPE_INPUT)&&(item[choice].type!=NM_TYPE_INPUT_MENU))
  1341.                 Int3(); 
  1342.             break;
  1343.         #endif
  1344.  
  1345.         }
  1346.  
  1347.         if ( choice > -1 )    {
  1348.             int ascii;
  1349.  
  1350.             if ( ((item[choice].type==NM_TYPE_INPUT)||((item[choice].type==NM_TYPE_INPUT_MENU)&&(item[choice].group==1)) )&& (old_choice==choice) )    {
  1351.                 if ( k==KEY_LEFT || k==KEY_BACKSP || k==KEY_PAD4 )    {
  1352.                     if (item[choice].value==-1) item[choice].value = strlen(item[choice].text);
  1353.                     if (item[choice].value > 0)
  1354.                         item[choice].value--;
  1355.                     item[choice].text[item[choice].value] = 0;
  1356.                     item[choice].redraw = 1;    
  1357.                 } else {
  1358.                     ascii = key_to_ascii(k);
  1359.                     if ((ascii < 255 ) && (item[choice].value < item[choice].text_len ))
  1360.                     {
  1361.                         int allowed;
  1362.  
  1363.                         if (item[choice].value==-1) {
  1364.                             item[choice].value = 0;
  1365.                         }
  1366.  
  1367.                         allowed = char_allowed(ascii);
  1368.  
  1369.                         if (!allowed && ascii==' ' && char_allowed('_')) {
  1370.                             ascii = '_';
  1371.                             allowed=1;
  1372.                         }
  1373.  
  1374.                         if (allowed) {
  1375.                             item[choice].text[item[choice].value++] = ascii;
  1376.                             item[choice].text[item[choice].value] = 0;
  1377.                             item[choice].redraw=1;    
  1378.                         }
  1379.                     }
  1380.                 }
  1381.             } else if ((item[choice].type!=NM_TYPE_INPUT) && (item[choice].type!=NM_TYPE_INPUT_MENU) ) {
  1382.                 ascii = key_to_ascii(k);
  1383.                 if (ascii < 255 ) {
  1384.                     int choice1 = choice;
  1385.                     ascii = toupper(ascii);
  1386.                     do {
  1387.                         int i,ch;
  1388.                         choice1++;
  1389.                         if (choice1 >= nitems ) choice1=0;
  1390.                         for (i=0;(ch=item[choice1].text[i])!=0 && ch==' ';i++);
  1391.                         if ( ( (item[choice1].type==NM_TYPE_MENU) ||
  1392.                                  (item[choice1].type==NM_TYPE_CHECK) ||
  1393.                                  (item[choice1].type==NM_TYPE_RADIO) ||
  1394.                                  (item[choice1].type==NM_TYPE_NUMBER) ||
  1395.                                  (item[choice1].type==NM_TYPE_SLIDER) )
  1396.                                 && (ascii==toupper(ch)) )    {
  1397.                             k = 0;
  1398.                             choice = choice1;
  1399.                             if (old_choice>-1)
  1400.                                 item[old_choice].redraw=1;
  1401.                             item[choice].redraw=1;
  1402.                         }
  1403.                     } while (choice1 != choice );
  1404.                 }    
  1405.             }
  1406.  
  1407.             if ( (item[choice].type==NM_TYPE_NUMBER) || (item[choice].type==NM_TYPE_SLIDER))     {
  1408.                 int ov=item[choice].value;
  1409.                 switch( k ) {
  1410.                 case KEY_PAD4:
  1411.                   case KEY_LEFT:
  1412.                   case KEY_MINUS:
  1413.                 case KEY_MINUS+KEY_SHIFTED:
  1414.                 case KEY_PADMINUS:
  1415.                     item[choice].value -= 1;
  1416.                     break;
  1417.                   case KEY_RIGHT:
  1418.                 case KEY_PAD6:
  1419.                   case KEY_EQUAL:
  1420.                 case KEY_EQUAL+KEY_SHIFTED:
  1421.                 case KEY_PADPLUS:
  1422.                     item[choice].value++;
  1423.                     break;
  1424.                 case KEY_PAGEUP:
  1425.                 case KEY_PAD9:
  1426.                 case KEY_SPACEBAR:
  1427.                     item[choice].value += 10;
  1428.                     break;
  1429.                 case KEY_PAGEDOWN:
  1430.                 case KEY_BACKSP:
  1431.                 case KEY_PAD3:
  1432.                     item[choice].value -= 10;
  1433.                     break;
  1434.                 }
  1435.                 if (ov!=item[choice].value)
  1436.                     item[choice].redraw=1;
  1437.             }
  1438.     
  1439.         }
  1440.  
  1441.         gr_set_current_canvas(bg.menu_canvas);
  1442.         // Redraw everything...
  1443.         for (i=0; i<nitems; i++ )    {
  1444.             if (item[i].redraw)    {
  1445.                 draw_item( &bg, &item[i], (i==choice && !all_text) );
  1446.                 item[i].redraw=0;
  1447.             }
  1448.             else if (i==choice && (item[i].type==NM_TYPE_INPUT || (item[i].type==NM_TYPE_INPUT_MENU && item[i].group)))
  1449.                 update_cursor( &item[i]);
  1450.         }
  1451.  
  1452.         if ( gr_palette_faded_out )    {
  1453.             gr_palette_fade_in( gr_palette, 32, 0 );
  1454.         }
  1455.     }
  1456.     
  1457.     // Restore everything...
  1458.     gr_set_current_canvas(bg.menu_canvas);
  1459.     if ( filename == NULL )    {
  1460.         // Save the background under the menu...
  1461.         gr_bitmap(0, 0, bg.saved);     
  1462.         gr_free_bitmap(bg.saved);
  1463.         free( bg.background );
  1464.     } else {
  1465.         gr_bitmap(0, 0, bg.background);     
  1466.         gr_free_bitmap(bg.background);
  1467.     }
  1468.  
  1469.     gr_free_sub_canvas( bg.menu_canvas );
  1470.  
  1471.     gr_set_current_canvas( NULL );            
  1472.     grd_curcanv->cv_font    = save_font;
  1473.     gr_set_current_canvas( save_canvas );            
  1474.     keyd_repeat = old_keyd_repeat;
  1475.  
  1476.     game_flush_inputs();
  1477.  
  1478.     if (time_stopped)
  1479.         start_time();
  1480.  
  1481. //NO_SOUND_PAUSE    if ( sound_stopped )
  1482. //NO_SOUND_PAUSE        digi_resume_all();
  1483.  
  1484.     return choice;
  1485.     
  1486. }
  1487.  
  1488.  
  1489. int nm_messagebox1( char *title, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int nchoices, ... )
  1490. {
  1491.     int i;
  1492.     char * format;
  1493.     va_list args;
  1494.     char *s;
  1495.     char nm_text[MESSAGEBOX_TEXT_SIZE];
  1496.     newmenu_item nm_message_items[5];
  1497.  
  1498.     va_start(args, nchoices );
  1499.  
  1500.     Assert( nchoices <= 5 );
  1501.  
  1502.     for (i=0; i<nchoices; i++ )    {
  1503.         s = va_arg( args, char * );
  1504.         nm_message_items[i].type = NM_TYPE_MENU; nm_message_items[i].text = s;
  1505.     }
  1506.     format = va_arg( args, char * );
  1507.     sprintf(    nm_text, "" );
  1508.     vsprintf(nm_text,format,args);
  1509.     va_end(args);
  1510.  
  1511.     Assert(strlen(nm_text) < MESSAGEBOX_TEXT_SIZE);
  1512.  
  1513.     return newmenu_do( title, nm_text, nchoices, nm_message_items, subfunction );
  1514. }
  1515.  
  1516. int nm_messagebox( char *title, int nchoices, ... )
  1517. {
  1518.     int i;
  1519.     char * format;
  1520.     va_list args;
  1521.     char *s;
  1522.     char nm_text[MESSAGEBOX_TEXT_SIZE];
  1523.     newmenu_item nm_message_items[5];
  1524.  
  1525.     va_start(args, nchoices );
  1526.  
  1527.     Assert( nchoices <= 5 );
  1528.  
  1529.     for (i=0; i<nchoices; i++ )    {
  1530.         s = va_arg( args, char * );
  1531.         nm_message_items[i].type = NM_TYPE_MENU; nm_message_items[i].text = s;
  1532.     }
  1533.     format = va_arg( args, char * );
  1534.     sprintf(    nm_text, "" );
  1535.     vsprintf(nm_text,format,args);
  1536.     va_end(args);
  1537.  
  1538.     Assert(strlen(nm_text) < MESSAGEBOX_TEXT_SIZE );
  1539.  
  1540.     return newmenu_do( title, nm_text, nchoices, nm_message_items, NULL );
  1541. }
  1542.  
  1543.  
  1544.  
  1545.  
  1546. void newmenu_file_sort( int n, char *list )
  1547. {
  1548.     int i, j, incr;
  1549.     char t[14];
  1550.  
  1551.     incr = n / 2;
  1552.     while( incr > 0 )        {
  1553.         for (i=incr; i<n; i++ )        {
  1554.             j = i - incr;
  1555.             while (j>=0 )            {
  1556.                 if (strncmp(&list[j*14], &list[(j+incr)*14], 12) > 0)                {
  1557.                     memcpy( t, &list[j*14], 13 );
  1558.                     memcpy( &list[j*14], &list[(j+incr)*14], 13 );
  1559.                     memcpy( &list[(j+incr)*14], t, 13 );
  1560.                     j -= incr;
  1561.                 }
  1562.                 else
  1563.                     break;
  1564.             }
  1565.         }
  1566.         incr = incr / 2;
  1567.     }
  1568. }
  1569.  
  1570. void delete_player_saved_games(char * name)
  1571. {
  1572.     int i;
  1573.     char filename[16];
  1574.     
  1575.     for (i=0;i<10; i++)    {
  1576.         sprintf( filename, "%s.sg%d", name, i );
  1577.         unlink( filename );
  1578.     }
  1579. }
  1580.  
  1581. #define MAX_FILES 100
  1582.  
  1583. int MakeNewPlayerFile(int allow_abort);
  1584.  
  1585. int newmenu_get_filename( char * title, char * filespec, char * filename, int allow_abort_flag )
  1586. {
  1587.     int i;
  1588.     struct find_t find;
  1589.     int NumFiles=0, key,done, citem, ocitem;
  1590.     char * filenames = NULL;
  1591.     int NumFiles_displayed = 8;
  1592.     int first_item = -1, ofirst_item;
  1593.     int old_keyd_repeat = keyd_repeat;
  1594.     int player_mode=0;
  1595.     int demo_mode=0;
  1596.     int demos_deleted=0;
  1597.     int initialized = 0;
  1598.     int exit_value = 0;
  1599.     int w_x, w_y, w_w, w_h;
  1600.  
  1601.     filenames = malloc( MAX_FILES * 14 );
  1602.     if (filenames==NULL) return 0;
  1603.  
  1604.     citem = 0;
  1605.     keyd_repeat = 1;
  1606.  
  1607.     if (!stricmp( filespec, "*.plr" ))
  1608.         player_mode = 1;
  1609.     else if (!stricmp( filespec, "*.dem" ))
  1610.         demo_mode = 1;
  1611.  
  1612. ReadFileNames:
  1613.     done = 0;
  1614.     NumFiles=0;
  1615.  
  1616.     if (player_mode)    {
  1617.         strncpy( &filenames[NumFiles*14], TXT_CREATE_NEW, 13 );
  1618.         NumFiles++;
  1619.     }
  1620.  
  1621.     if( !_dos_findfirst( filespec, 0, &find ) )    {
  1622.         do    {
  1623.             if (NumFiles<MAX_FILES)    {
  1624.                 strncpy( &filenames[NumFiles*14], find.name, 13 );
  1625.                 if ( player_mode )    {
  1626.                     char * p;
  1627.                     p = strchr(&filenames[NumFiles*14],'.');
  1628.                     if (p) *p = '\0';
  1629.                 }
  1630.                 NumFiles++;
  1631.             } else {
  1632.                 break;
  1633.             }
  1634.         } while( !_dos_findnext( &find ) );
  1635.     }
  1636.  
  1637. #ifdef USE_CD
  1638.     // Seach CD for files if demo_mode and cd_mode
  1639.     if ( strlen(destsat_cdpath) && demo_mode )    {
  1640.         char temp_spec[128];
  1641.         strcpy( temp_spec, destsat_cdpath );
  1642.         strcat( temp_spec, filespec );
  1643.  
  1644.         if( !_dos_findfirst( temp_spec, 0, &find ) )    {
  1645.             do    {
  1646.                 if (NumFiles<MAX_FILES)    {
  1647.  
  1648.                     for (i=0; i<NumFiles; i++ )    {
  1649.                         if (!stricmp( &filenames[i*14], find.name ))
  1650.                             break;
  1651.                     }
  1652.                     if ( i < NumFiles ) continue;        // Don't use same demo twice!
  1653.  
  1654.                     strncpy( &filenames[NumFiles*14], find.name, 13 );
  1655.                     if ( player_mode )    {
  1656.                         char * p;
  1657.                         p = strchr(&filenames[NumFiles*14],'.');
  1658.                         if (p) *p = '\0';
  1659.                     }
  1660.                     NumFiles++;
  1661.                 } else {
  1662.                     break;
  1663.                 }
  1664.             } while( !_dos_findnext( &find ) );
  1665.         }
  1666.     }
  1667. #endif
  1668.  
  1669.     if ( (NumFiles < 1) && demos_deleted )    {
  1670.         exit_value = 0;
  1671.         goto ExitFileMenu;
  1672.     }
  1673.     if ( (NumFiles < 1) && demo_mode ) {
  1674.         nm_messagebox( NULL, 1, TXT_OK, "%s %s\n%s", TXT_NO_DEMO_FILES, TXT_USE_F5, TXT_TO_CREATE_ONE);
  1675.         exit_value = 0;
  1676.         goto ExitFileMenu;
  1677.     }
  1678.  
  1679.     if ( (NumFiles < 2) && player_mode ) {
  1680.         citem = 0;
  1681.         goto ExitFileMenuEarly;
  1682.     }
  1683.  
  1684.     if ( NumFiles<1 )    {
  1685.         nm_messagebox( NULL, 1, "Ok", "%s\n '%s' %s", TXT_NO_FILES_MATCHING, filespec, TXT_WERE_FOUND);
  1686.         exit_value = 0;
  1687.         goto ExitFileMenu;
  1688.     }
  1689.  
  1690.     if (!initialized) {    
  1691.         set_screen_mode(SCREEN_MENU);
  1692.         gr_set_current_canvas(NULL);
  1693.  
  1694.         w_w = 230 - 90 + 1 + 30;
  1695.         w_h = 170 - 30 + 1 + 30;
  1696.     
  1697.         if ( w_w > 320 ) w_w = 320;
  1698.         if ( w_h > 200 ) w_h = 200;
  1699.     
  1700.         w_x = (grd_curcanv->cv_bitmap.bm_w-w_w)/2;
  1701.         w_y = (grd_curcanv->cv_bitmap.bm_h-w_h)/2;
  1702.     
  1703.         if ( w_x < 0 ) w_x = 0;
  1704.         if ( w_y < 0 ) w_y = 0;
  1705.  
  1706.         gr_bm_bitblt(320, 200, 0, 0, 0, 0, &(grd_curcanv->cv_bitmap), &(VR_offscreen_buffer->cv_bitmap) );
  1707.         nm_draw_background( w_x,w_y,w_x+w_w-1,w_y+w_h-1 );
  1708.  
  1709.         grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_3];
  1710.         gr_string( 0x8000, w_y+10, title );
  1711.         initialized = 1;
  1712.     }
  1713.  
  1714.     if ( !player_mode )    {
  1715.         newmenu_file_sort( NumFiles, filenames );
  1716.     } else {
  1717.         newmenu_file_sort( NumFiles-1, &filenames[14] );        // Don't sort first one!
  1718.         for ( i=0; i<NumFiles; i++ )    {
  1719.             if (!stricmp(Players[Player_num].callsign, &filenames[i*14]) )
  1720.                 citem = i;
  1721.         }
  1722.     }
  1723.  
  1724.     while(!done)    {
  1725.         ocitem = citem;
  1726.         ofirst_item = first_item;
  1727.         key = key_inkey();
  1728.         switch(key)    {
  1729.         case KEY_PRINT_SCREEN:         save_screen_shot(0); break;
  1730.         case KEY_CTRLED+KEY_D:
  1731.             if ( ((player_mode)&&(citem>0)) || ((demo_mode)&&(citem>=0)) )    {
  1732.                 int x = 1;
  1733.                 if (player_mode)
  1734.                     x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "%s %s?", TXT_DELETE_PILOT, &filenames[citem*14]+((player_mode && filenames[citem*14]=='$')?1:0) );
  1735.                 else if (demo_mode)
  1736.                     x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "%s %s?", TXT_DELETE_DEMO, &filenames[citem*14]+((demo_mode && filenames[citem*14]=='$')?1:0) );
  1737.                  if (x==0)    {
  1738.                     char * p;
  1739.                     int ret;
  1740.                     p = &filenames[(citem*14)+strlen(&filenames[citem*14])];
  1741.                     if (player_mode)
  1742.                         *p = '.';
  1743.                     ret = unlink( &filenames[citem*14] );
  1744.                     if (player_mode)
  1745.                         *p = 0;
  1746.  
  1747.                     if ((!ret) && player_mode)    {
  1748.                         delete_player_saved_games( &filenames[citem*14] );
  1749.                     }
  1750.  
  1751.                     if (ret) {
  1752.                         if (player_mode)
  1753.                             nm_messagebox( NULL, 1, TXT_OK, "%s %s %s", TXT_COULDNT, TXT_DELETE_PILOT, &filenames[citem*14]+((player_mode && filenames[citem*14]=='$')?1:0) );
  1754.                         else if (demo_mode)
  1755.                             nm_messagebox( NULL, 1, TXT_OK, "%s %s %s", TXT_COULDNT, TXT_DELETE_DEMO, &filenames[citem*14]+((demo_mode && filenames[citem*14]=='$')?1:0) );
  1756.                     } else if (demo_mode)
  1757.                         demos_deleted = 1;
  1758.                     first_item = -1;
  1759.                     goto ReadFileNames;
  1760.                 }
  1761.             }
  1762.             break;
  1763.         case KEY_HOME:
  1764.         case KEY_PAD7:
  1765.             citem = 0;
  1766.             break;
  1767.         case KEY_END:
  1768.         case KEY_PAD1:
  1769.             citem = NumFiles-1;
  1770.             break;
  1771.         case KEY_UP:
  1772.         case KEY_PAD8:
  1773.             citem--;            
  1774.             break;
  1775.         case KEY_DOWN:
  1776.         case KEY_PAD2:
  1777.             citem++;            
  1778.             break;
  1779.          case KEY_PAGEDOWN:
  1780.         case KEY_PAD3:
  1781.             citem += NumFiles_displayed;
  1782.             break;
  1783.         case KEY_PAGEUP:
  1784.         case KEY_PAD9:
  1785.             citem -= NumFiles_displayed;
  1786.             break;
  1787.         case KEY_ESC:
  1788.             if (allow_abort_flag) {
  1789.                 citem = -1;
  1790.                 done = 1;
  1791.             }
  1792.             break;
  1793.         case KEY_ENTER:
  1794.         case KEY_PADENTER:
  1795.             done = 1;
  1796.             break;
  1797.         default:    
  1798.             {
  1799.                 int ascii = key_to_ascii(key);
  1800.                 if ( ascii < 255 )    {
  1801.                     int cc,cc1;
  1802.                     cc=cc1=citem+1;
  1803.                     if (cc1 < 0 )  cc1 = 0;
  1804.                     if (cc1 >= NumFiles )  cc1 = 0;
  1805.                     while(1) {
  1806.                         if ( cc < 0 ) cc = 0;
  1807.                         if ( cc >= NumFiles ) cc = 0;
  1808.                         if ( citem == cc ) break;
  1809.     
  1810.                         if ( toupper(filenames[cc*14]) == toupper(ascii) )    {
  1811.                             citem = cc;
  1812.                             break;
  1813.                         }
  1814.                         cc++;
  1815.                     }
  1816.                 }
  1817.             }
  1818.         }
  1819.         if ( done ) break;
  1820.  
  1821.  
  1822.         if (citem<0)
  1823.             citem=0;
  1824.  
  1825.         if (citem>=NumFiles)
  1826.             citem = NumFiles-1;
  1827.  
  1828.         if (citem< first_item)
  1829.             first_item = citem;
  1830.  
  1831.         if (citem>=( first_item+NumFiles_displayed))
  1832.             first_item = citem-NumFiles_displayed+1;
  1833.  
  1834.         if (NumFiles <= NumFiles_displayed )
  1835.              first_item = 0;
  1836.  
  1837.         if (first_item>NumFiles-NumFiles_displayed)
  1838.             first_item = NumFiles-NumFiles_displayed;
  1839.         if (first_item < 0 ) first_item = 0;
  1840.  
  1841.         if (ofirst_item != first_item )    {
  1842.             gr_setcolor( BM_XRGB( 0,0,0)  );
  1843.             for (i=first_item; i<first_item+NumFiles_displayed; i++ )    {
  1844.                 int w, h, aw, y;
  1845.                 y = (i-first_item)*12+w_y+45;
  1846.                 if ( i >= NumFiles )    {
  1847.                     gr_setcolor( BM_XRGB(0,0,0));
  1848.                     gr_rect( 100, y-1, 220, y+11 );
  1849.                 } else {
  1850.                     if ( i == citem )    
  1851.                         grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_2];
  1852.                     else    
  1853.                         grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_1];
  1854.                     gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
  1855.                     gr_rect( 100, y-1, 220, y+11 );
  1856.                     gr_string( 105, y, (&filenames[i*14])+((player_mode && filenames[i*14]=='$')?1:0)  );
  1857.                 }
  1858.             }        
  1859.         } else if ( citem != ocitem )    {
  1860.             int w, h, aw, y;
  1861.  
  1862.             i = ocitem;
  1863.             if ( (i>=0) && (i<NumFiles) )    {
  1864.                 y = (i-first_item)*12+w_y+45;
  1865.                 if ( i == citem )    
  1866.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_2];
  1867.                 else    
  1868.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_1];
  1869.                 gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
  1870.                 gr_rect( 100, y-1, 220, y+11 );
  1871.                 gr_string( 105, y, (&filenames[i*14])+((player_mode && filenames[i*14]=='$')?1:0)  );
  1872.             }
  1873.             i = citem;
  1874.             if ( (i>=0) && (i<NumFiles) )    {
  1875.                 y = (i-first_item)*12+w_y+45;
  1876.                 if ( i == citem )    
  1877.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_2];
  1878.                 else    
  1879.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_1];
  1880.                 gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
  1881.                 gr_rect( 100, y-1, 220, y+11 );
  1882.                 gr_string( 105, y, (&filenames[i*14])+((player_mode && filenames[i*14]=='$')?1:0)  );
  1883.             }
  1884.         }
  1885.     }
  1886.  
  1887. ExitFileMenuEarly:
  1888.     if ( citem > -1 )    {
  1889.         strncpy( filename, (&filenames[citem*14])+((player_mode && filenames[citem*14]=='$')?1:0), 13 );
  1890.         exit_value = 1;
  1891.     } else {
  1892.         exit_value = 0;
  1893.     }                                             
  1894.  
  1895. ExitFileMenu:
  1896.     keyd_repeat = old_keyd_repeat;
  1897.  
  1898.     if ( initialized )    {
  1899.         gr_bm_bitblt(320, 200, 0, 0, 0, 0, &(VR_offscreen_buffer->cv_bitmap), &(grd_curcanv->cv_bitmap) );
  1900.     }
  1901.  
  1902.     if ( filenames )
  1903.         free(filenames);
  1904.  
  1905.     return exit_value;
  1906.  
  1907. }
  1908.  
  1909.  
  1910. // Example listbox callback function...
  1911. // int lb_callback( int * citem, int *nitems, char * items[], int *keypress )
  1912. // {
  1913. //     int i;
  1914. // 
  1915. //     if ( *keypress = KEY_CTRLED+KEY_D )    {
  1916. //         if ( *nitems > 1 )    {
  1917. //             unlink( items[*citem] );        // Delete the file
  1918. //             for (i=*citem; i<*nitems-1; i++ )    {
  1919. //                 items[i] = items[i+1];
  1920. //             }
  1921. //             *nitems = *nitems - 1;
  1922. //             free( items[*nitems] );
  1923. //             items[*nitems] = NULL;
  1924. //             return 1;    // redraw;
  1925. //         }
  1926. //            *keypress = 0;
  1927. //     }            
  1928. //     return 0;
  1929. // }
  1930.  
  1931. #define LB_ITEMS_ON_SCREEN 8
  1932.  
  1933. int newmenu_listbox( char * title, int nitems, char * items[], int allow_abort_flag, int (*listbox_callback)( int * citem, int *nitems, char * items[], int *keypress ) )
  1934. {
  1935.     return newmenu_listbox1( title, nitems, items, allow_abort_flag, 0, listbox_callback );
  1936. }
  1937.  
  1938. int newmenu_listbox1( char * title, int nitems, char * items[], int allow_abort_flag, int default_item, int (*listbox_callback)( int * citem, int *nitems, char * items[], int *keypress ) )
  1939. {
  1940.     int i;
  1941.     int done, ocitem,citem, ofirst_item, first_item, key, redraw;
  1942.     int old_keyd_repeat = keyd_repeat;
  1943.     int width, height, wx, wy, title_height;
  1944.     keyd_repeat = 1;
  1945.  
  1946.     set_screen_mode(SCREEN_MENU);
  1947.     gr_set_current_canvas(NULL);
  1948.     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_3];
  1949.  
  1950.     width = 0;
  1951.     for (i=0; i<nitems; i++ )    {
  1952.         int w, h, aw;
  1953.         gr_get_string_size( items[i], &w, &h, &aw );        
  1954.         if ( w > width )
  1955.             width = w;
  1956.     }
  1957.     height = 12 * LB_ITEMS_ON_SCREEN;
  1958.  
  1959.     {
  1960.         int w, h, aw;
  1961.         gr_get_string_size( title, &w, &h, &aw );        
  1962.         if ( w > width )
  1963.             width = w;
  1964.         title_height = h + 5;
  1965.     }
  1966.         
  1967.     width += 10;
  1968.     if ( width > 320 - 30 )
  1969.         width = 320 - 30;
  1970.     
  1971.     wx = (grd_curcanv->cv_bitmap.bm_w-width)/2;
  1972.     wy = (grd_curcanv->cv_bitmap.bm_h-(height+title_height))/2 + title_height;
  1973.     if ( wy < title_height )
  1974.         wy = title_height;
  1975.  
  1976.     gr_bm_bitblt(320, 200, 0, 0, 0, 0, &(grd_curcanv->cv_bitmap), &(VR_offscreen_buffer->cv_bitmap) );
  1977.     nm_draw_background( wx-15,wy-title_height-15,wx+width+15,wy+height+15 );
  1978.  
  1979.     gr_string( 0x8000, wy - title_height, title );
  1980.  
  1981.     done = 0;
  1982.     citem = default_item;
  1983.     if ( citem < 0 ) citem = 0;
  1984.     if ( citem >= nitems ) citem = 0;
  1985.  
  1986.     first_item = -1;
  1987.  
  1988.     while(!done)    {
  1989.         ocitem = citem;
  1990.         ofirst_item = first_item;
  1991.         key = key_inkey();
  1992.  
  1993.         if ( listbox_callback )
  1994.             redraw = (*listbox_callback)(&citem, &nitems, items, &key );
  1995.         else
  1996.             redraw = 0;
  1997.  
  1998.         if ( key<-1 ) {
  1999.             citem = key;
  2000.             key = -1;
  2001.             done = 1;
  2002.         }
  2003.  
  2004.         switch(key)    {
  2005.         case KEY_PRINT_SCREEN:         
  2006.             save_screen_shot(0); 
  2007.             break;
  2008.         case KEY_HOME:
  2009.         case KEY_PAD7:
  2010.             citem = 0;
  2011.             break;
  2012.         case KEY_END:
  2013.         case KEY_PAD1:
  2014.             citem = nitems-1;
  2015.             break;
  2016.         case KEY_UP:
  2017.         case KEY_PAD8:
  2018.             citem--;            
  2019.             break;
  2020.         case KEY_DOWN:
  2021.         case KEY_PAD2:
  2022.             citem++;            
  2023.             break;
  2024.          case KEY_PAGEDOWN:
  2025.         case KEY_PAD3:
  2026.             citem += LB_ITEMS_ON_SCREEN;
  2027.             break;
  2028.         case KEY_PAGEUP:
  2029.         case KEY_PAD9:
  2030.             citem -= LB_ITEMS_ON_SCREEN;
  2031.             break;
  2032.         case KEY_ESC:
  2033.             if (allow_abort_flag) {
  2034.                 citem = -1;
  2035.                 done = 1;
  2036.             }
  2037.             break;
  2038.         case KEY_ENTER:
  2039.         case KEY_PADENTER:
  2040.             done = 1;
  2041.             break;
  2042.         default:    
  2043.             if ( key > 0 )    {
  2044.                 int ascii = key_to_ascii(key);
  2045.                 if ( ascii < 255 )    {
  2046.                     int cc,cc1;
  2047.                     cc=cc1=citem+1;
  2048.                     if (cc1 < 0 )  cc1 = 0;
  2049.                     if (cc1 >= nitems )  cc1 = 0;
  2050.                     while(1) {
  2051.                         if ( cc < 0 ) cc = 0;
  2052.                         if ( cc >= nitems ) cc = 0;
  2053.                         if ( citem == cc ) break;
  2054.     
  2055.                         if ( toupper( items[cc][0] ) == toupper(ascii) )    {
  2056.                             citem = cc;
  2057.                             break;
  2058.                         }
  2059.                         cc++;
  2060.                     }
  2061.                 }
  2062.             }
  2063.         }
  2064.         if ( done ) break;
  2065.  
  2066.         if (citem<0)
  2067.             citem=0;
  2068.  
  2069.         if (citem>=nitems)
  2070.             citem = nitems-1;
  2071.  
  2072.         if (citem< first_item)
  2073.             first_item = citem;
  2074.  
  2075.         if (citem>=( first_item+LB_ITEMS_ON_SCREEN))
  2076.             first_item = citem-LB_ITEMS_ON_SCREEN+1;
  2077.  
  2078.         if (nitems <= LB_ITEMS_ON_SCREEN )
  2079.              first_item = 0;
  2080.  
  2081.         if (first_item>nitems-LB_ITEMS_ON_SCREEN)
  2082.             first_item = nitems-LB_ITEMS_ON_SCREEN;
  2083.         if (first_item < 0 ) first_item = 0;
  2084.  
  2085.         if ( (ofirst_item != first_item) || redraw)    {
  2086.             gr_setcolor( BM_XRGB( 0,0,0)  );
  2087.             for (i=first_item; i<first_item+LB_ITEMS_ON_SCREEN; i++ )    {
  2088.                 int w, h, aw, y;
  2089.                 y = (i-first_item)*12+wy;
  2090.                 if ( i >= nitems )    {
  2091.                     gr_setcolor( BM_XRGB(0,0,0));
  2092.                     gr_rect( wx, y-1, wx+width-1, y+11 );
  2093.                 } else {
  2094.                     if ( i == citem )    
  2095.                         grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_2];
  2096.                     else    
  2097.                         grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_1];
  2098.                     gr_get_string_size(items[i], &w, &h, &aw  );
  2099.                     gr_rect( wx, y-1, wx+width-1, y+11 );
  2100.                     gr_string( wx+5, y, items[i]  );
  2101.                 }
  2102.             }        
  2103.         } else if ( citem != ocitem )    {
  2104.             int w, h, aw, y;
  2105.  
  2106.             i = ocitem;
  2107.             if ( (i>=0) && (i<nitems) )    {
  2108.                 y = (i-first_item)*12+wy;
  2109.                 if ( i == citem )    
  2110.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_2];
  2111.                 else    
  2112.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_1];
  2113.                 gr_get_string_size(items[i], &w, &h, &aw  );
  2114.                 gr_rect( wx, y-1, wx+width-1, y+11 );
  2115.                 gr_string( wx+5, y, items[i]  );
  2116.             }
  2117.             i = citem;
  2118.             if ( (i>=0) && (i<nitems) )    {
  2119.                 y = (i-first_item)*12+wy;
  2120.                 if ( i == citem )    
  2121.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_2];
  2122.                 else    
  2123.                     grd_curcanv->cv_font = Gamefonts[GFONT_MEDIUM_1];
  2124.                 gr_get_string_size( items[i], &w, &h, &aw  );
  2125.                 gr_rect( wx, y-1, wx+width-1, y+11 );
  2126.                 gr_string( wx+5, y, items[i]  );
  2127.             }
  2128.         }
  2129.     }
  2130.     keyd_repeat = old_keyd_repeat;
  2131.  
  2132.     gr_bm_bitblt(320, 200, 0, 0, 0, 0, &(VR_offscreen_buffer->cv_bitmap), &(grd_curcanv->cv_bitmap) );
  2133.  
  2134.     return citem;
  2135. }
  2136.  
  2137.  
  2138. int newmenu_filelist( char * title, char * filespec, char * filename )
  2139. {
  2140.     int i, NumFiles;
  2141.     char * Filenames[MAX_FILES];
  2142.     char FilenameText[MAX_FILES][14];
  2143.     struct find_t find;
  2144.  
  2145.     NumFiles = 0;
  2146.     if( !_dos_findfirst( filespec, 0, &find ) )    {
  2147.         do    {
  2148.             if (NumFiles<MAX_FILES)    {
  2149.                 strncpy( FilenameText[NumFiles], find.name, 13 );
  2150.                 Filenames[NumFiles] = FilenameText[NumFiles];
  2151.                 NumFiles++;
  2152.             } else {
  2153.                 break;
  2154.             }
  2155.         } while( !_dos_findnext( &find ) );
  2156.     }
  2157.  
  2158.     i = newmenu_listbox( title, NumFiles, Filenames, 1, NULL );
  2159.     if ( i > -1 )    {
  2160.         strcpy( filename, Filenames[i] );
  2161.         return 1;
  2162.     } 
  2163.     return 0;
  2164. }
  2165.  
  2166. 
  2167.