home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / mac / macmenus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-25  |  45.6 KB  |  1,893 lines  |  [TEXT/KAHL]

  1. /* Menus and commands for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10. #include "print.h"
  11. #include "macconq.h"
  12. extern WindowPtr playersetupwin;
  13. extern int gameinited;
  14.  
  15. #undef DEF_CMD
  16. #define DEF_CMD(letter,name,args,FN,help) extern void FN(void);
  17.  
  18. #include "cmd.def"
  19.  
  20. #include "maccmd.def"
  21.  
  22. extern int do_one_give(Unit *unit);
  23. extern int do_one_take(Unit *unit);
  24. extern int do_one_return(Unit *unit);
  25. extern int do_one_detonate(Unit *unit);
  26. extern int do_one_give_unit(Unit *unit);
  27. extern int do_one_detach(Unit *unit);
  28. extern int do_one_disband(Unit *unit);
  29.  
  30. extern int do_one_clear_plan(Unit *unit);
  31. extern int do_one_dir_move(Unit *unit);
  32. extern int do_one_dir_multiple_move(Unit *unit);
  33. extern int do_one_set_name(Unit *unit);
  34.  
  35. static void sanitize_for_menu(char *str, char *outstr);
  36.  
  37. static void resign_the_game(int forced);
  38.  
  39. int forcedtoresign;
  40.  
  41. int modal_construction = FALSE;
  42.  
  43. WindowPtr window_behind_construction;
  44.  
  45. extern Feature *featurelist;
  46.  
  47. #ifdef THINK_C
  48. #include <profile.h>
  49. #endif
  50.  
  51. int Profile = FALSE;
  52.  
  53. #define SetMenuItemText SetItem
  54. #define InsertMenuItem InsMenuItem
  55.  
  56. #define side_may_select(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
  57.  
  58. #define valid_selection(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
  59.  
  60. #define menus_tweakable() ((!beforestart && !endofgame) || (gameinited && dside->designer))
  61.  
  62. #define MAXWINDOWS 100
  63.  
  64. extern int gamestatesafe;
  65. extern int interfacestatesafe;
  66.  
  67. char *cursavename = NULL;
  68.  
  69. MenuHandle mapviewmenu = nil;
  70. MenuHandle listviewmenu = nil;
  71. MenuHandle closeupviewmenu = nil;
  72.  
  73. MenuHandle utypemenu = nil;
  74. MenuHandle ttypemenu = nil;
  75. MenuHandle mtypemenu = nil;
  76. MenuHandle sidemenu = nil;
  77. MenuHandle aitypemenu = nil;
  78.  
  79. MenuHandle featuremenu = nil;
  80. MenuHandle optterrmenu = nil;
  81.  
  82. WindowPtr *winmenuwins;
  83.  
  84. int numwindows;
  85.  
  86. Map *worldmap = NULL;
  87.  
  88. WindowPtr worldmapwin = nil;
  89.  
  90. /* Set up all the menus, at least in their basic form. */
  91.  
  92. void
  93. init_menus()
  94. {
  95.     int i;
  96.     Handle menubar;
  97.     MenuHandle menu;
  98.  
  99.     menubar = GetNewMBar(mbMain);
  100.     SetMenuBar(menubar);
  101.     /* Add the DAs etc as usual. */
  102.     menu = GetMHandle(mApple);
  103.     if (menu != nil)
  104.       AddResMenu(menu, 'DRVR');
  105.     /* Get the different versions of the view menu. */
  106.     mapviewmenu = GetMenu(mViewMap);
  107.     listviewmenu = GetMenu(mViewList);
  108.     closeupviewmenu = GetMenu(mViewCloseup);
  109.     /* Init submenus and popups. */
  110.     menu = GetMenu(mViewFontSizes);
  111.     if (menu != nil)
  112.       InsertMenu(menu, -1);
  113.     menu = GetMenu(mMagnifications);
  114.     if (menu != nil)
  115.       InsertMenu(menu, -1);
  116.     menu = GetMenu(mViewWeather);
  117.     if (menu != nil)
  118.       InsertMenu(menu, -1);
  119.     sidemenu = GetMenu(mSides);
  120.     if (sidemenu != nil)
  121.       InsertMenu(sidemenu, -1);
  122.     utypemenu = GetMenu(mUnitTypes);
  123.     if (utypemenu != nil)
  124.       InsertMenu(utypemenu, -1);
  125.     mtypemenu = GetMenu(mMaterialTypes);
  126.     if (mtypemenu != nil)
  127.       InsertMenu(mtypemenu, -1);
  128.     ttypemenu = GetMenu(mTerrainTypes);
  129.     if (ttypemenu != nil)
  130.       InsertMenu(ttypemenu, -1);
  131.     aitypemenu = GetMenu(mAITypes);
  132.     if (aitypemenu != nil)
  133.       InsertMenu(aitypemenu, -1);
  134.     featuremenu = GetMenu(mFeatures);
  135.     if (featuremenu != nil)
  136.       InsertMenu(featuremenu, -1);
  137.     optterrmenu = GetMenu(mOptTerrainTypes);
  138.     if (optterrmenu != nil)
  139.       InsertMenu(optterrmenu, -1);
  140.     /* Init the support for the Windows menu. */
  141.     winmenuwins = (WindowPtr *) xmalloc(MAXWINDOWS * sizeof(WindowPtr));
  142.     for (i = 0; i < MAXWINDOWS; ++i)
  143.       winmenuwins[i] = nil;
  144.     numwindows = 0;
  145.     /* Done fiddling with menus, draw them. */
  146.     DrawMenuBar();
  147. }
  148.  
  149. /* Add a menu item that can be used to go to the given window.  Set the window title
  150.    here too, ensures that the two match. */
  151.  
  152. void
  153. add_window_menu_item(char *name, WindowPtr win)
  154. {
  155.     MenuHandle menu;
  156.     Str255 tmpstr;
  157.  
  158.     if (numwindows < MAXWINDOWS) {
  159.         c2p(name, tmpstr);
  160.         SetWTitle(win, tmpstr);
  161.         winmenuwins[numwindows++] = win;
  162.         menu = GetMHandle(mWindows);
  163.         if (menu != nil)
  164.           AppendMenu(menu, tmpstr);
  165.     }
  166. }
  167.  
  168. /* Remove the menu item that can be used to select a given window. */
  169.  
  170. void
  171. remove_window_menu_item(WindowPtr win)
  172. {
  173.     int i, found = FALSE, next = 0;
  174.     Str255 tmpstr;
  175.     MenuHandle menu;
  176.  
  177.     /* Search for the window and remove it from the array of windows
  178.        that have menu items. */
  179.     for (i = 0; i < numwindows; ++i) {
  180.         if (!found && winmenuwins[i] == win) {
  181.             found = TRUE;
  182.         }
  183.         if (found && i < numwindows - 1) {
  184.             /* Shift the other windows down. */
  185.             winmenuwins[i] = winmenuwins[i + 1];
  186.         }
  187.     }
  188.     /* This routine gets called for all windows, so get out of here
  189.        if this window is not one of those in the menu. */
  190.     if (!found)
  191.       return;
  192.     --numwindows;
  193.     /* Trash the existing window menu. */
  194.     menu = GetMHandle(mWindows);
  195.     if (menu != nil) {
  196.         DeleteMenu(mWindows);
  197.         ReleaseResource((Handle) menu);
  198.     }
  199.     /* Build a new version starting with the resource. */
  200.     menu = GetMenu(mWindows);
  201.     if (menu != nil) {
  202.         for (i = 0; i < numwindows; ++i) {
  203.             GetWTitle(winmenuwins[i], tmpstr);
  204.             AppendMenu(menu, tmpstr);
  205.         }
  206.         /* Glue a view menu on after the windows menu. */
  207.         if (GetMHandle(mViewMap) != nil)
  208.           next = mViewMap;
  209.         if (GetMHandle(mViewList) != nil)
  210.           next = mViewList;
  211.         InsertMenu(menu, next);
  212.     }
  213.     DrawMenuBar();
  214. }
  215.  
  216. /* Fill up the side menu. */
  217.  
  218. void
  219. build_side_menu()
  220. {
  221.     char *title;
  222.     Side *side2;
  223.     Str255 tmpstr;
  224.  
  225.     if (sidemenu != nil && CountMItems(sidemenu) < 1) {
  226.         for_all_sides(side2) {
  227.             title = shortest_side_title(side2, spbuf);
  228.             sanitize_for_menu(title, tmpstr);
  229.             AppendMenu(sidemenu, tmpstr);
  230.             EnableItem(sidemenu, side_number(side2));
  231.         }
  232.         if (1 /* independent units possible in this game */) {
  233.             AppendMenu(sidemenu, "\pindependent");
  234.         }
  235.     }
  236. }
  237.  
  238. void
  239. update_side_menu(Side *side2)
  240. {
  241.     char *title;
  242.     Str255 tmpstr;
  243.  
  244.     title = shortest_side_title(side2, spbuf);
  245.     sanitize_for_menu(title, tmpstr);
  246.     SetMenuItemText(sidemenu, side_number(side2), tmpstr);
  247. }
  248.  
  249. void
  250. build_unit_type_menu()
  251. {
  252.     int u;
  253.     Str255 tmpstr;
  254.  
  255.     if (utypemenu != nil && CountMItems(utypemenu) < 1) {
  256.         for_all_unit_types(u) {
  257.             sanitize_for_menu(u_type_name(u), tmpstr);
  258.             AppendMenu(utypemenu, tmpstr);
  259.             EnableItem(utypemenu, u + 1);
  260.         }
  261.     }
  262. }
  263.  
  264. void
  265. build_material_type_menu()
  266. {
  267.     int m;
  268.     Str255 tmpstr;
  269.  
  270.     if (mtypemenu != nil && CountMItems(mtypemenu) < 1 && nummtypes > 0) {
  271.         for_all_material_types(m) {
  272.             sanitize_for_menu(m_type_name(m), tmpstr);
  273.             AppendMenu(mtypemenu, tmpstr);
  274.             EnableItem(mtypemenu, m + 1);
  275.         }
  276.     }
  277. }
  278.  
  279. void
  280. build_terrain_type_menu()
  281. {
  282.     int t;
  283.     Str255 tmpstr;
  284.  
  285.     if (ttypemenu != nil && CountMItems(ttypemenu) < 1) {
  286.         for_all_terrain_types(t) {
  287.             sanitize_for_menu(t_type_name(t), tmpstr);
  288.             AppendMenu(ttypemenu, tmpstr);
  289.             EnableItem(ttypemenu, t);
  290.         }
  291.     }
  292. }
  293.  
  294. void
  295. build_ai_type_menu()
  296. {
  297.     if (aitypemenu != nil && CountMItems(aitypemenu) < 1) {
  298.         AppendMenu(aitypemenu, "\pNone");
  299.         EnableItem(aitypemenu, 1);
  300.         AppendMenu(aitypemenu, "\pMplayer");
  301.         EnableItem(aitypemenu, 2);
  302.     }
  303. }
  304.  
  305. void
  306. build_feature_menu()
  307. {
  308.     int i = 1;
  309.     char *name;
  310.     Str255 tmpstr;
  311.     Feature *feature;
  312.     MenuHandle oldmenu, newmenu = nil;
  313.  
  314.     if (featuremenu != nil) {
  315.         if (CountMItems(featuremenu) >= 1) {
  316.             /* Trash the existing feature menu. */
  317.             oldmenu = GetMHandle(mFeatures);
  318.             if (oldmenu != nil) {
  319.                 DeleteMenu(mFeatures);
  320.                 ReleaseResource((Handle) oldmenu);
  321.                 /* Build a new version starting with the resource. */
  322.                 if ((newmenu = GetMenu(mFeatures)) != nil) {
  323.                     featuremenu = newmenu;
  324.                 }
  325.             }
  326.         }
  327.         AppendMenu(featuremenu, "\pNo Feature");
  328.         EnableItem(featuremenu, i++);
  329.         for (feature = featurelist; feature != NULL; feature = feature->next) {
  330.             name = feature_desc(feature, spbuf);
  331.             sanitize_for_menu(name, tmpstr);
  332.             AppendMenu(featuremenu, tmpstr);
  333.             EnableItem(featuremenu, i++);
  334.         }
  335.         if (newmenu != nil) {
  336.             InsertMenu(featuremenu, -1);
  337.         }
  338.     }
  339. }
  340.  
  341. void
  342. build_optional_terrain_type_menu()
  343. {
  344.     int t;
  345.     Str255 tmpstr;
  346.  
  347.     if (optterrmenu != nil && CountMItems(optterrmenu) < 1) {
  348.         for_all_terrain_types(t) {
  349.             if (!t_is_cell(t)) {
  350.                 sanitize_for_menu(t_type_name(t), tmpstr);
  351.                 AppendMenu(optterrmenu, tmpstr);
  352.                 EnableItem(optterrmenu, t);
  353.             }
  354.         }
  355.         if (CountMItems(optterrmenu) < 1)
  356.           optterrmenu = nil;
  357.     }
  358. }
  359.  
  360. /* Alter the feature menu to reflect a changed or new feature. */
  361.  
  362. void
  363. update_feature_menu(Feature *feature)
  364. {
  365.     char *desc;
  366.     Str255 tmpstr;
  367.  
  368.     desc = feature_desc(feature, spbuf);
  369.     sanitize_for_menu(desc, tmpstr);
  370.     if (feature->id + 1 > CountMItems(featuremenu)) {
  371.         AppendMenu(featuremenu, tmpstr);
  372.         EnableItem(featuremenu, feature->id + 1);
  373.     } else {
  374.         SetMenuItemText(featuremenu, feature->id + 1, tmpstr);
  375.     }
  376. }
  377.  
  378. /* This removes chars that are specially recognized by the Menu Manager.
  379.    Has to be done so that strange game-defined names don't scramble the
  380.    menus; innocuous because this affects only the appearance in the menu. */
  381.  
  382. static void
  383. sanitize_for_menu(char *str, char *outstr)
  384. {
  385.     int i = 0;
  386.  
  387.     /* Replace special chars with blanks. */
  388.     for (i = 0; str[i] != '\0' && i < 255; ++i) {
  389.         switch (str[i]) {
  390.             case ';':
  391.             case '!':
  392.             case '<':
  393.             case '/':
  394.             case '(':
  395.             /* I don't think closing parens are special, but since the
  396.                (presumed) matching open paren is gone, might as well get
  397.                rid of the close also. */
  398.             case ')':
  399.                 outstr[i + 1] = ' ';
  400.                 break;
  401.             default:
  402.                 outstr[i + 1] = str[i];
  403.                 break;
  404.         }
  405.     }
  406.     outstr[i + 1] = '\0';
  407.     /* Replace a leading hyphen with an underscore. */
  408.     if (outstr[1] == '-')
  409.       outstr[1] = '_';
  410.     outstr[0] = i;
  411. }
  412.  
  413. /* Decipher and do a menu command. */
  414.  
  415. void
  416. do_menu_command(long which)
  417. {
  418.     short menuid, menuitem, daRefNum;
  419.     Str255 daname;
  420.     WindowPtr win;
  421.     Map *map;
  422.  
  423.     menuid = HiWord(which);
  424.     menuitem = LoWord(which);
  425.     DGprintf("menu %d, item %d\n", menuid, menuitem);
  426.     map = map_from_window(FrontWindow());    
  427.     switch (menuid) {
  428.         case mApple:
  429.             switch (menuitem) {
  430.                 case miAppleAbout:
  431.                     do_about_box();
  432.                     break;
  433.                 case miAppleHelp:
  434.                     help_dialog();
  435.                     break;
  436.                 case miAppleInstructions:
  437.                     instructions_dialog();
  438.                     break;
  439.                 default:
  440.                     GetItem(GetMHandle(mApple), menuitem, daname);
  441.                     daRefNum = OpenDeskAcc(daname);
  442.             }
  443.             break;
  444.         case mFile:
  445.             switch (menuitem) {
  446.                 case miFileNew:
  447.                     /* (should reset state of everything first) */
  448.                     new_game_dialog();
  449.                     break;
  450.                 case miFileOpen:
  451.                     /* (should reset state of everything first) */
  452.                     open_game_dialog();
  453.                     break;
  454.                 case miFileConnect:
  455.                     connect_game_dialog();
  456.                     break;
  457.                 case miFileSave:
  458.                     save_the_game(FALSE, FALSE);
  459.                     break;
  460.                 case miFileSaveAs:    
  461.                     save_the_game(TRUE, FALSE);
  462.                     break;
  463.                 case miFilePreferences:
  464.                     set_preferences();
  465.                     break;
  466.                 case miFilePageSetup:
  467.                     do_page_setup_mi();
  468.                     break;
  469.                 case miFilePrintWindow:
  470.                     do_print_mi();
  471.                     break;
  472.                 case miFileResign:
  473.                     resign_the_game(FALSE);
  474.                     break;
  475.                 case miFileQuit:
  476.                     quit_the_game();
  477.                     break;
  478.             }
  479.             break;
  480.         case mEdit:
  481.             /* handledbyda = SystemEdit(menuitem-1); */
  482.             switch (menuitem)  {
  483.                 case miEditCut:
  484.                     /* disband_selection(); */
  485.                     /* (should depend on whether this is a map or a text field) */
  486.                     break;
  487.                 case miEditSelectAll:
  488.                     do_select_all_mi();
  489.                     break;
  490. #ifdef DESIGNERS
  491.                 case miEditDesign:
  492.                     do_design();
  493.                     break;
  494. #endif
  495.             }
  496.             break;
  497.         case mFind:
  498.             switch (menuitem) {
  499.                 case miFindPrevious:
  500.                     do_find_previous_mi();
  501.                     break;
  502.                 case miFindNext:
  503.                     do_find_next_mi();
  504.                     break;
  505.                 case miFindLocation:
  506.                     do_find_location_mi();
  507.                     break;
  508.                 case miFindUnitByName:
  509.                     do_find_unit_by_name_mi();
  510.                     break;
  511.                 case miFindSelected:
  512.                     do_find_selected_mi();
  513.                     break;
  514.             }
  515.             break;
  516.         case mPlay:
  517.             switch (menuitem) {
  518.                 case miPlayCloseup:
  519.                     do_closeup_mi();
  520.                     break;
  521.                 case miPlayMove:
  522.                     do_move_mi();
  523.                     break;
  524.                 case miPlayPatrol:
  525.                     do_patrol_mi();
  526.                     break;
  527.                 case miPlayReturn:
  528.                     do_return();
  529.                     break;
  530.                 case miPlayWake:
  531.                     do_wake();
  532.                     break;
  533.                 case miPlaySleep:
  534.                     do_sleep();
  535.                     break;
  536.                 case miPlayDoneMoving:
  537.                     do_reserve();
  538.                     break;
  539.                 case miPlayBuild:
  540.                     do_build();
  541.                     break;
  542.                 case miPlayRepair:
  543.                     do_repair_mi();
  544.                     break;
  545.                 case miPlayAttack:
  546.                     do_attack_mi();
  547.                     break;
  548.                 case miPlayOverrun:
  549.                     do_overrun_mi();
  550.                     break;
  551.                 case miPlayFire:
  552.                     do_fire_mi();
  553.                     break;
  554.                 case miPlayFireInto:
  555.                     do_fire_into_mi();
  556.                     break;
  557.                 case miPlayDetonate:
  558.                     do_detonate_mi();
  559.                     break;
  560.                 case miPlayTake:
  561.                     do_take_mi();
  562.                     break;
  563.                 case miPlayDrop:
  564.                     break;
  565.                 case miPlayGive:
  566.                     /* has submenu mSides */
  567.                     break;
  568.                 case miPlayDisband:
  569.                     do_disband();
  570.                     break;
  571.                 case miPlayRename:
  572.                     do_name();
  573.                     break;
  574.             }
  575.             break;
  576.         case mSides:
  577.             do_give_unit_mi(menuitem);
  578.             break;
  579.         case mSide:
  580.             switch (menuitem) {
  581.                 case miSideCloseup:
  582.                     break;
  583.                 case miSideFinishedTurn:
  584.                     finish_turn(dside);
  585.                     break;
  586.                 case miSideMoveOnClick:
  587.                     moveonclick_mi();
  588.                     break;
  589.                 case miSideAutoSelect:
  590.                     autoselect_mi();
  591.                     break;
  592.                 case miSideAutoFinish:
  593.                     /* Toggle auto-finish for turns. */
  594.                     set_autofinish(dside, !dside->autofinish);
  595.                     break;
  596.                 case miSideSound:
  597.                     playsounds = !playsounds;
  598.                     break;
  599.                 case miSideRename:
  600.                     side_rename_dialog(dside);
  601.                     break;
  602.             }
  603.             break;
  604.         case mWindows:
  605.             switch (menuitem) {
  606.                 case miWindowsGame:
  607.                     if (gamewin == nil) {
  608.                         create_game_window();
  609.                     }
  610.                     ShowWindow(gamewin);
  611.                     SelectWindow(gamewin);
  612.                     break;
  613.                 case miWindowsHistory:
  614.                     if (historywin == nil) {
  615.                         create_history_window();
  616.                     }
  617.                     ShowWindow(historywin);
  618.                     SelectWindow(historywin);
  619.                     break;
  620.                 case miWindowsConstruction:
  621.                     enable_construction();
  622.                     break;
  623.                 /* should have agreements list etc handling here also */
  624.                 case miWindowsNewList:
  625.                     create_list();
  626.                     break;
  627.                 case miWindowsNewMap:
  628.                     create_map(5 /* should be a pref */);
  629.                     break;
  630.                 case miWindowsWorldMap:
  631.                     if (worldmapwin == nil) {
  632.                         int power, winwid = 200;
  633.  
  634.                         for (power = 0; power < NUMPOWERS; ++power) {
  635.                             if (area.width * hws[power] <= winwid
  636.                                 && area.width * hws[power+1] > winwid) break;
  637.                         }
  638.                         worldmap = create_map(power);
  639.                         worldmap->drawothermaps = TRUE;
  640.                         /* (should be in survey mode too?) */
  641.                         worldmapwin = worldmap->window;
  642.                     }
  643.                     ShowWindow(worldmapwin);
  644.                     SelectWindow(worldmapwin);
  645.                     break;
  646.                 default:
  647.                     win = winmenuwins[menuitem - miWindowsFirst];
  648.                     if (win != nil) {
  649.                         SelectWindow(win);
  650.                     }
  651.                     break;
  652.             }
  653.             break;
  654.         case mViewMap:
  655.             if (map == NULL) break;
  656.             switch (menuitem)  {
  657.                 case miViewCloser:
  658.                     magnify_map(map, 1);
  659.                     break;
  660.                 case miViewFarther:
  661.                     magnify_map(map, -1);
  662.                     break;
  663.                 case miViewNames:
  664.                     toggle_map_names(map);
  665.                     break;
  666.                 case miViewPeople:
  667.                     toggle_map_people(map);
  668.                     break;
  669.                 case miViewElevations:
  670.                     toggle_map_elevations(map);
  671.                     break;
  672.                 case miViewDaylight:
  673.                     toggle_map_lighting(map);
  674.                     break;
  675.                 case miViewCoverage:
  676.                     toggle_map_coverage(map);
  677.                     break;
  678.                 case miViewGrid:
  679.                     toggle_map_grid(map);
  680.                     break;
  681.                 case miViewTopline:
  682.                     toggle_map_topline(map);
  683.                     break;
  684.                 case miViewOtherMaps:
  685.                     toggle_map_other_maps(map);
  686.                     break;
  687.             }
  688.             break;
  689.         case mViewWeather:
  690.             if (map == NULL) break;
  691.             switch (menuitem)  {
  692.                 case miWeatherTemperature:
  693.                     toggle_map_temperature(map);
  694.                     break;
  695.                 case miWeatherWinds:
  696.                     toggle_map_winds(map);
  697.                     break;
  698.                 case miWeatherClouds:
  699.                     toggle_map_clouds(map);
  700.                     break;
  701.                 case miWeatherStorms:
  702.                     toggle_map_storms(map);
  703.                     break;
  704.             }
  705.             break;
  706.         case mViewList:
  707.             switch (menuitem)  {
  708.                 case miViewByType:
  709.                     set_list_sorting(list_from_window(FrontWindow()), bytype, menuitem);
  710.                     break;
  711.                 case miViewByName:
  712.                     set_list_sorting(list_from_window(FrontWindow()), byname, menuitem);
  713.                     break;
  714.                 case miViewBySide:
  715.                     set_list_sorting(list_from_window(FrontWindow()), byside, menuitem);
  716.                     break;
  717.                 case miViewByActOrder:
  718.                     set_list_sorting(list_from_window(FrontWindow()), byactorder, menuitem);
  719.                     break;
  720.                 case miViewByLocation:
  721.                     set_list_sorting(list_from_window(FrontWindow()), bylocation, menuitem);
  722.                     break;
  723.                 case miViewIconSize:
  724.                     toggle_list_large_icons(list_from_window(FrontWindow()));
  725.                     break;
  726.             }
  727.             break;
  728.         case mAITypes:
  729.             switch (menuitem) {
  730.                 case 1:
  731.                     if (side_has_ai(dside)) {
  732.                         set_side_ai(dside, NULL);
  733.                     }
  734.                     break;
  735.                 case 2:
  736.                     if (!side_has_ai(dside)) {
  737.                         set_side_ai(dside, "mplayer");
  738.                     }
  739.                     break;
  740.             }
  741.             break;
  742.         case mMagnifications:
  743.             if (map == NULL) break;
  744.             set_map_mag(map, menuitem - 1);
  745.             break;
  746.         case mMaterialTypes:
  747.             if (map == NULL) break;
  748.             toggle_map_materials(map, menuitem - 1);
  749.             break;
  750.         case mOptTerrainTypes:
  751.             if (map == NULL) break;
  752.             toggle_map_aux_terrain(map, map->auxterraintypes[menuitem]);
  753.             break;
  754.     }
  755.     HiliteMenu(0);
  756. }
  757.  
  758. /* Display the "About..." box. */
  759.  
  760. void
  761. do_about_box()
  762. {
  763.     short ditem;
  764.     Str255 tmpstr;
  765.     WindowPtr win;
  766.     PicHandle pic;
  767.     short itemtype;  Handle itemhandle;  Rect itemrect;
  768.  
  769.     win = GetNewDialog(dAbout, NULL, (DialogPtr) -1L);
  770.     /* Fill in the kernel's version and copyright. */
  771.     GetDItem(win, diAboutVersion, &itemtype, &itemhandle, &itemrect);
  772.     c2p(version_string(), tmpstr);
  773.     SetIText(itemhandle, tmpstr);
  774.     GetDItem(win, diAboutCopyright, &itemtype, &itemhandle, &itemrect);
  775.     c2p(copyright_string(), tmpstr);
  776.     SetIText(itemhandle, tmpstr);
  777.     /* Substitute a color picture if we've got a color/gray screen. */
  778.     if (hasColorQD) {
  779.         GetDItem(win, diAboutPicture, &itemtype, &itemhandle, &itemrect);
  780.         if ((pic = (PicHandle) GetResource('PICT', pSplashColor)) != nil) {
  781.             SetDItem(win, diAboutPicture, itemtype, (Handle) pic, &itemrect);
  782.         }
  783.     }
  784.     ShowWindow(win);
  785.     SelectWindow(win);
  786.     draw_default_button(win, diAboutOK);
  787.     SetCursor(&QD(arrow));
  788.     ModalDialog(NULL, &ditem);
  789.     /* Just return, no matter what input. */
  790.     HideWindow(win);
  791.     DisposDialog(win);
  792. }
  793.  
  794. /* This routine does both "save" and "save as". */
  795.  
  796. void
  797. save_the_game(int askname, int quitting)
  798. {
  799.     Point pnt;
  800.     char namebuf[256];
  801.     Str255 tmpstr;
  802.     SFReply reply;
  803.  
  804. #ifdef DESIGNERS
  805.     /* Do the selective save only if we're not shutting down Xconq. */
  806.     if (dside->designer && !quitting) {
  807.         designer_save_dialog();
  808.         return;
  809.     }
  810. #endif
  811.     if (askname || cursavename == NULL) {
  812.         if (cursavename == NULL)
  813.           cursavename = saved_game_filename();
  814.         /* Collect the file and path to save to. */
  815.         SetPt(&pnt, 100, 100);
  816.         c2p(cursavename, tmpstr);
  817.         SFPutFile(pnt, "\p", tmpstr, (DlgHookProcPtr) nil, &reply);
  818.         if (!reply.good)
  819.           return;
  820.         /* Make the location of the file be the current volume. */
  821.         SetVol(reply.fName, reply.vRefNum);
  822.         p2c(((char *) reply.fName), namebuf);
  823.         cursavename = copy_string(namebuf);
  824.     }
  825.     SetCursor(*watchcursor);
  826.     write_entire_game_state(cursavename);
  827.     set_game_file_type(cursavename);
  828.     SetCursor(&QD(arrow));
  829. }
  830.  
  831. void
  832. set_preferences()
  833. {
  834.     short done = FALSE, ditem;
  835.     DialogPtr win;
  836.     short itemtype;  Handle itemhandle;  Rect itemrect;
  837.     extern int checkpointinterval;
  838.  
  839.     win = GetNewDialog(dPreferences, NULL, (DialogPtr) -1L);
  840.     /* Set the current preferences into the items. */
  841.     GetDItem(win, diPrefsGrid, &itemtype, &itemhandle, &itemrect);
  842.     SetCtlValue((ControlHandle) itemhandle, default_draw_grid);
  843.     GetDItem(win, diPrefsNames, &itemtype, &itemhandle, &itemrect);
  844.     SetCtlValue((ControlHandle) itemhandle, default_draw_names);
  845.     GetDItem(win, diPrefsCheckpoint, &itemtype, &itemhandle, &itemrect);
  846.     SetCtlValue((ControlHandle) itemhandle, (checkpointinterval > 0));
  847.     ShowWindow(win);
  848.     while (!done) {
  849.         SetCursor(&QD(arrow));
  850.         ModalDialog(NULL, &ditem);
  851.         switch (ditem) {
  852.             case diPrefsOK:
  853.                 /* Actually change the program's variables. */
  854.                 GetDItem(win, diPrefsGrid, &itemtype, &itemhandle, &itemrect);
  855.                 default_draw_grid = GetCtlValue((ControlHandle) itemhandle);
  856.                 GetDItem(win, diPrefsNames, &itemtype, &itemhandle, &itemrect);
  857.                 default_draw_names = GetCtlValue((ControlHandle) itemhandle);
  858.                 GetDItem(win, diPrefsCheckpoint, &itemtype, &itemhandle, &itemrect);
  859.                 checkpointinterval = (GetCtlValue((ControlHandle) itemhandle) ? 5 : 0);
  860.                 /* Seems like as good a time as any to remember these settings! */
  861.                 save_preferences();
  862.                 /* Fall into next case. */
  863.             case diPrefsCancel:
  864.                 done = TRUE;
  865.                 break;
  866.             case diPrefsGrid:
  867.             case diPrefsNames:
  868.                 /* Toggle check boxes. */
  869.                 GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
  870.                 SetCtlValue((ControlHandle) itemhandle, !GetCtlValue((ControlHandle) itemhandle));
  871.                 break;
  872.             case diPrefsCheckpoint:
  873.                 GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
  874.                 SetCtlValue((ControlHandle) itemhandle, !GetCtlValue((ControlHandle) itemhandle));
  875.                 /* Should enable/disable interval-setting ditems. */
  876.                 break;
  877.             case diPrefsInterval:
  878.                 break;
  879.         }
  880.     }
  881.     DisposDialog(win);
  882. }
  883.  
  884. /*THPrint printrecordhandle = nil;*/
  885.  
  886. void
  887. maybe_init_print()
  888. {
  889. /*    if (printrecordhandle == nil) {
  890.         printrecordhandle = (THPrint) NewHandle(sizeof(TPrint));
  891.         PrOpen();
  892.         PrintDefault(printrecordhandle);
  893.     } */
  894. }
  895.  
  896. void
  897. do_page_setup_mi()
  898. {
  899.     maybe_init_print();
  900. /*    PrStlDialog(printrecordhandle); */
  901. }
  902.  
  903. /* Handle printing.  What gets printed depends on which window is in front. */
  904.  
  905. void
  906. do_print_mi()
  907. {
  908.     Map *map;
  909.     List *list;
  910.  
  911.     maybe_init_print();
  912. /*    if (!PrJobDialog(printrecordhandle)) return; */
  913.     if ((map = map_from_window(FrontWindow())) != NULL) {
  914.         print_map(map);
  915.     } else if ((list = list_from_window(FrontWindow())) != NULL) {
  916.         print_list(list);
  917.     } else {
  918.         /* (should at least be able to print help) */
  919.     }
  920. }
  921.  
  922. static void
  923. resign_the_game(int forced)
  924. {
  925.     Str255 tmpstr;
  926.  
  927.     sprintf(tmpbuf, "Other players");
  928.     c2p(tmpbuf, tmpstr);
  929.     ParamText(tmpstr, "\p", "\p", "\p");
  930.     switch (CautionAlert(aResignGame, nil)) {
  931.         case aiResignGameOK:
  932.             forcedtoresign = forced;
  933.             resign_game(dside, NULL);
  934.             break;
  935.         case aiResignGameWillingToDraw:
  936.             set_willing_to_draw(dside, TRUE);
  937.             break;
  938.         case aiResignGameCancel:
  939.             break;
  940.     }
  941. }
  942.  
  943. /* Attempt to quit. */
  944.  
  945. void
  946. quit_the_game()
  947. {
  948.     int confirmresign = FALSE;
  949.     extern int gamestatesafe, interfacestatesafe;
  950.  
  951.     if (endofgame) {
  952.         /* Game is already over, nothing to save, just leave. */
  953.         ExitToShell();
  954.     } else if (!gamestatesafe || !interfacestatesafe) {
  955.         switch (CautionAlert(aQuitGame, nil)) {
  956.             case aiQuitGameOK:
  957.                 if (all_others_willing_to_save(dside)) {
  958.                     SetCursor(*watchcursor);
  959.                     save_the_game(FALSE, TRUE);
  960.                     SetCursor(&QD(arrow));
  961.                     ExitToShell();
  962.                 } else {
  963.                     set_willing_to_save(dside, TRUE);
  964.                     /* (should warn that not all were willing to save) */
  965.                 }
  966.                 break;
  967.             case aiQuitGameDontSave:
  968.                 if (all_others_willing_to_quit(dside)) {
  969.                     ExitToShell();
  970.                 } else {
  971.                     /* Can only get out by resigning. */
  972.                     confirmresign = TRUE;
  973.                 }
  974.                 break;
  975.             case aiQuitGameCancel:
  976.                 break;
  977.         }
  978.     } else {
  979.         /* (should still confirm that we're not avoiding our fate?) */
  980.         ExitToShell();
  981.     }
  982.     if (confirmresign) {
  983.         resign_the_game(TRUE);
  984.     }
  985. }
  986.  
  987. void
  988. do_select_all_mi()
  989. {
  990.     Map *map;
  991.     Unit *unit;
  992.     
  993.     if ((map = map_from_window(FrontWindow())) != NULL) {
  994.         for_all_units(unit) {
  995.             if (side_may_select(unit)) {
  996.                 select_unit_on_map(map, unit);
  997.             }
  998.         }
  999.         /* Do all the drawing at once. */
  1000.         draw_selections(map);
  1001.     }
  1002. }
  1003.  
  1004. void
  1005. do_find_previous_mi()
  1006. {
  1007.     Map *map;
  1008.     
  1009.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1010.         select_previous_unit(map);
  1011.     }
  1012. }
  1013.  
  1014. void
  1015. do_find_next_mi()
  1016. {
  1017.     Map *map;
  1018.     
  1019.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1020.         select_next_mover(map);
  1021.     }
  1022. }
  1023.  
  1024. /* (should ask for x,y coords, focus/center on that position) */
  1025.  
  1026. void
  1027. do_find_location_mi()
  1028. {
  1029.     Map *map;
  1030.     
  1031.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1032.     }
  1033. }
  1034.  
  1035. /* (should ask for a textual name/select from a gazetteer, scroll to that unit) */
  1036.  
  1037. void
  1038. do_find_unit_by_name_mi()
  1039. {
  1040.     Map *map;
  1041.     
  1042.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1043.     }
  1044. }
  1045.  
  1046. void
  1047. do_find_selected_mi()
  1048. {
  1049.     Map *map;
  1050.     List *list;
  1051.     UnitCloseup *closeup;
  1052.     
  1053.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1054.         /* (what would this mean? - scroll to avg of selected units?) */
  1055.     } else if ((list = list_from_window(FrontWindow())) != NULL) {
  1056.         scroll_to_selected_unit_in_list(list);
  1057.     } else if ((closeup = unit_closeup_from_window(FrontWindow())) != NULL) {
  1058.         if (closeup->unit != NULL)
  1059.           scroll_best_map_to_unit(closeup->unit);
  1060.     } else if (constructionwin == FrontWindow()) {
  1061.         scroll_to_selected_construction_unit();
  1062.     } else {
  1063.         /* nothing to do */
  1064.     }
  1065. }
  1066.  
  1067. /* Menu items/commands for unit play action. */
  1068.  
  1069. void
  1070. apply_to_all_selected(int (*fn)(Unit *unit), int beepfailure)
  1071. {
  1072.     int i, rslt, numcould = 0, numnot = 0;
  1073.     Map *map;  List *list;  UnitCloseup *closeup;
  1074.     Unit *unit;
  1075.  
  1076.     if (fn == NULL)
  1077.       return;
  1078.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1079.         for (i = 0; i < map->numselections; ++i) {
  1080.             unit = map->selections[i];
  1081.             if (in_play(unit)) {
  1082.                 rslt = (*fn)(unit);
  1083.                 if (rslt)
  1084.                   ++numcould;
  1085.                 else
  1086.                   ++numnot;
  1087.             }
  1088.         }
  1089.     } else if ((list = list_from_window(FrontWindow())) != NULL) {
  1090.         if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
  1091.             rslt = (*fn)(unit);
  1092.             if (rslt)
  1093.               ++numcould;
  1094.             else
  1095.               ++numnot;
  1096.         }
  1097.     } else if ((closeup = unit_closeup_from_window(FrontWindow())) != NULL) {
  1098.         if ((unit = closeup->unit) != NULL) {
  1099.             rslt = (*fn)(unit);
  1100.             if (rslt)
  1101.               ++numcould;
  1102.             else
  1103.               ++numnot;
  1104.         }
  1105.     }
  1106.     /* If everybody that was asked to do this couldn't, beep once. */
  1107.     if (beepfailure && numcould == 0 && numnot > 0)
  1108.       beep();
  1109. }
  1110.  
  1111. void
  1112. do_closeup_mi()
  1113. {
  1114.     int i;
  1115.     Map *map;  List *list;  UnitCloseup *unitcloseup;
  1116.     Unit *unit;
  1117.     
  1118.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1119.         for (i = 0; i < map->numselections; ++i) {
  1120.             if ((unit = map->selections[i]) != NULL) {
  1121.                 if ((unitcloseup = find_unit_closeup(unit)) != NULL) {
  1122.                     ShowWindow(unitcloseup->window);
  1123.                     SelectWindow(unitcloseup->window);
  1124.                 } else {
  1125.                     create_unit_closeup(unit);
  1126.                 }
  1127.             }
  1128.         }
  1129.     } else if ((list = list_from_window(FrontWindow())) != NULL) {
  1130.         if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
  1131.             if ((unitcloseup = find_unit_closeup(unit)) != NULL) {
  1132.                 ShowWindow(unitcloseup->window);
  1133.                 SelectWindow(unitcloseup->window);
  1134.             } else {
  1135.                 create_unit_closeup(unit);
  1136.             }
  1137.         }
  1138.     } else if ((unitcloseup = unit_closeup_from_window(FrontWindow())) != NULL) {
  1139.         if ((unit = unitcloseup->unit) != NULL) {
  1140.             force_update(unitcloseup->window);
  1141.         }
  1142.     }
  1143. }
  1144.  
  1145. void
  1146. do_move_mi()
  1147. {
  1148.     beep();
  1149. }
  1150.  
  1151. void
  1152. do_patrol_mi()
  1153. {
  1154.     beep();
  1155. }
  1156.  
  1157. static int
  1158. do_one_ai_control(Unit *unit)
  1159. {
  1160.     if (unit->plan) {
  1161.         set_unit_ai_control(dside, unit, !unit->plan->aicontrol, FALSE);
  1162.         /* a hack */
  1163.         unit->plan->waitingfortasks = !unit->plan->aicontrol;
  1164.     }
  1165.     return TRUE;
  1166. }
  1167.  
  1168. void
  1169. do_ai_control_command()
  1170. {
  1171.     apply_to_all_selected(do_one_ai_control, TRUE);    
  1172. }
  1173.  
  1174. void
  1175. do_repair_mi()
  1176. {
  1177.     apply_to_all_selected(NULL, 0);    
  1178. }
  1179.  
  1180. /* (should find one unit to attack, do modal dialog if != 1) */
  1181.  
  1182. void
  1183. do_attack_mi()
  1184. {
  1185.     int i;
  1186.     Map *map;
  1187.     Unit *atker, *other;
  1188.     
  1189.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1190.         for (i = 0; i < map->numselections; ++i) {
  1191.             if ((atker = map->selections[i]) != NULL) {
  1192.                 for_all_units(other) {
  1193.                     if (other != atker
  1194.                         && other->side != atker->side
  1195.                         && distance(atker->x, atker->y, other->x, other->y) == 1) {
  1196.                             prep_attack_action(atker, atker, other, 100);
  1197.                             break;
  1198.                     }
  1199.                 }
  1200.             }
  1201.         }
  1202.     }
  1203. }
  1204.  
  1205. void
  1206. do_attack_command()
  1207. {
  1208.     int i, numcould = 0, numnot = 0;
  1209.     Point target;
  1210.     Map *map;
  1211.     Unit *atker, *other;
  1212.     
  1213.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1214.         GetMouse(&target);
  1215.         m_nearest_unit(map, target.h, target.v, &other);
  1216.         if (other != NULL) {
  1217.             for (i = 0; i < map->numselections; ++i) {
  1218.                 if ((atker = map->selections[i]) != NULL) {
  1219.                     if (other != atker
  1220.                         && other->side != atker->side) {
  1221.                         if (distance(atker->x, atker->y, other->x, other->y) <= 1
  1222.                             && valid(check_attack_action(atker, atker, other, 100))) {
  1223.                             prep_attack_action(atker, atker, other, 100);
  1224.                             ++numcould;
  1225.                         } else if (valid(check_fire_at_action(atker, atker, other, -1))) {
  1226.                             prep_fire_at_action(atker, atker, other, -1);
  1227.                             ++numcould;
  1228.                         } else {
  1229.                             ++numnot;
  1230.                         }
  1231.                     } else {
  1232.                     }
  1233.                 }
  1234.             }
  1235.         } else {
  1236.             /* (should let units fire into empty cell) */
  1237.         }
  1238.     }
  1239.     /* If nobody could do the action, beep once. */
  1240.     if (numcould == 0 && numnot > 0) beep();
  1241. }
  1242.  
  1243. void
  1244. do_overrun_mi()
  1245. {
  1246.     /* (should loop until mouse clicked in map) */
  1247.     beep();
  1248. }
  1249.  
  1250. void
  1251. do_fire_mi()
  1252. {
  1253.     if (map_modal == NO_MODAL) {
  1254.         map_modal = FIRE_MODAL;
  1255.     }
  1256. }
  1257.  
  1258. int
  1259. do_fire_command()
  1260. {
  1261.     int i, numcould = 0, numnot = 0;
  1262.     Point target;
  1263.     Map *map;
  1264.     Unit *atker, *other;
  1265.     
  1266.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1267.         GetMouse(&target);
  1268.         m_nearest_unit(map, target.h, target.v, &other);
  1269.         if (other != NULL) {
  1270.             for (i = 0; i < map->numselections; ++i) {
  1271.                 if ((atker = map->selections[i]) != NULL && valid_selection(atker)) {
  1272.                     if (other != atker
  1273.                         && other->side != atker->side
  1274.                         && valid(check_fire_at_action(atker, atker, other, -1))) {
  1275.                         prep_fire_at_action(atker, atker, other, -1);
  1276.                         ++numcould;
  1277.                     } else {
  1278.                         ++numnot;
  1279.                     }
  1280.                 }
  1281.             }
  1282.         } else {
  1283.             /* Just error out.  To bombard a cell, the player must do a fire-into
  1284.                command.  It might be useful to add an option that automatically tries
  1285.                firing into if no targets are visible, but if a player was trying to
  1286.                fire at a unit but got the cell slightly wrong, then the fire-into will
  1287.                happen anyway and the player loses the acp. */
  1288.             beep();
  1289.         }
  1290.     }
  1291.     /* If nobody could do the action, beep once. */
  1292.     if (numcould == 0 && numnot > 0) {
  1293.         beep();
  1294.         return FALSE;
  1295.     } else {
  1296.         return TRUE;
  1297.     }
  1298. }
  1299.  
  1300. void
  1301. do_fire_into_mi()
  1302. {
  1303.     if (map_modal == NO_MODAL) {
  1304.         map_modal = FIRE_INTO_MODAL;
  1305.     }
  1306. }
  1307.  
  1308. int
  1309. do_fire_into_command()
  1310. {
  1311.     int x, y, i, numcould = 0, numnot = 0;
  1312.     Point target;
  1313.     Map *map;
  1314.     Unit *atker;
  1315.     
  1316.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1317.         GetMouse(&target);
  1318.         if (m_nearest_cell(map, target.h, target.v, &x, &y)) {
  1319.             for (i = 0; i < map->numselections; ++i) {
  1320.                 if ((atker = map->selections[i]) != NULL && valid_selection(atker)) {
  1321.                     if (valid(check_fire_into_action(atker, atker, x, y, 0, -1))) {
  1322.                         prep_fire_into_action(atker, atker, x, y, 0, -1);
  1323.                         ++numcould;
  1324.                     } else {
  1325.                         ++numnot;
  1326.                     }
  1327.                 }
  1328.             }
  1329.         } else {
  1330.             beep();
  1331.         }
  1332.     }
  1333.     /* If nobody could do the action, beep once. */
  1334.     if (numcould == 0 && numnot > 0) {
  1335.         beep();
  1336.         return FALSE;
  1337.     } else {
  1338.         return TRUE;
  1339.     }
  1340. }
  1341.  
  1342. /* (should decide how to detonate based on selections and modal input) */
  1343.  
  1344. int
  1345. do_one_detonate(Unit *unit)
  1346. {
  1347.     if (valid(check_detonate_action(unit, unit, unit->x, unit->y, unit->z))) {
  1348.         prep_detonate_action(unit, unit, unit->x, unit->y, unit->z);
  1349.         return TRUE;
  1350.     }
  1351.     return FALSE;
  1352. }
  1353.  
  1354. void
  1355. do_detonate_mi()
  1356. {
  1357.     apply_to_all_selected(do_one_detonate, TRUE);
  1358. }
  1359.  
  1360. /* This command samples the current mouse to get the desired detonate location. */
  1361.  
  1362. void
  1363. do_detonate_command()
  1364. {
  1365.     int i, x, y;
  1366.     Point detpoint;
  1367.     Map *map;
  1368.     Unit *unit;
  1369.     
  1370.     if ((map = map_from_window(FrontWindow())) != NULL) {
  1371.         GetMouse(&detpoint);
  1372.         m_nearest_cell(map, detpoint.h, detpoint.v, &x, &y);
  1373.         for (i = 0; i < map->numselections; ++i) {
  1374.             if ((unit = map->selections[i]) != NULL) {
  1375.                 prep_detonate_action(unit, unit, x, y, unit->z);
  1376.             }
  1377.         }
  1378.     }
  1379. }
  1380.  
  1381. int
  1382. do_one_give(Unit *unit)
  1383. {
  1384.     give_supplies(unit, NULL, NULL);
  1385.     return 0;
  1386. }
  1387.  
  1388. Side *tmpcmdside;
  1389.  
  1390. int
  1391. do_one_give_unit(Unit *unit)
  1392. {
  1393.     if (unit->side == tmpcmdside)
  1394.       return 0;
  1395. #ifdef DESIGNERS
  1396.     if (dside->designer) {
  1397.         unit_changes_side(unit, tmpcmdside, -1, -1);
  1398.         update_unit_display(dside, unit, TRUE);
  1399.     } else
  1400. #endif /* DESIGNERS */
  1401.     {
  1402.         prep_change_side_action(unit, unit, tmpcmdside);
  1403.     }
  1404.     return TRUE;
  1405. }
  1406.  
  1407. void
  1408. do_give_unit_mi(int mi)
  1409. {
  1410.     Side *side = side_n(mi); /* note that side_n returns NULL for mi == numsides */
  1411.     
  1412.     apply_to_all_selected(do_one_give_unit, TRUE);
  1413. }
  1414.  
  1415. void
  1416. moveonclick_mi()
  1417. {
  1418.     Map *frontmap = map_from_window(FrontWindow());
  1419.  
  1420.     if (frontmap) {
  1421.         frontmap->moveonclick = !frontmap->moveonclick;
  1422.         /* (should force updates of map windows to reflect?) */
  1423.     } else {
  1424.         defaultmoveonclick = !defaultmoveonclick;
  1425.     }
  1426. }
  1427.  
  1428. int
  1429. do_one_take(Unit *unit)
  1430. {
  1431.     take_supplies(unit, NULL, NULL);
  1432.     return TRUE;
  1433. }
  1434.  
  1435. void
  1436. do_take_mi()
  1437. {
  1438.     apply_to_all_selected(do_one_take, TRUE);
  1439. }
  1440.  
  1441. void
  1442. autoselect_mi()
  1443. {
  1444.     Map *frontmap = map_from_window(FrontWindow());
  1445.     extern Unit *curunit;
  1446.  
  1447.     if (frontmap) {
  1448.         frontmap->autoselect = !frontmap->autoselect;
  1449.         frontmap->curunit = NULL; /* maybe not a good idea? */
  1450.         /* (should force updates of map windows to reflect?) */
  1451.     } else {
  1452.         defaultautoselect = !defaultautoselect;
  1453.     }
  1454. }
  1455.  
  1456. void
  1457. adjust_menu_item(MenuHandle menu, int item, int value)
  1458. {
  1459.     if (value)
  1460.       EnableItem(menu, item);
  1461.     else
  1462.       DisableItem(menu, item);
  1463. }
  1464.  
  1465. /* The state of menu items changes to reflect selected units, etc. */
  1466.  
  1467. void
  1468. adjust_menus()
  1469. {
  1470.     int i, m, t, numwins, menus_useful, numitems;
  1471.     MenuHandle menu;
  1472.     Map *frontmap;
  1473.     List *frontlist;
  1474.     UnitCloseup *frontcloseup;
  1475.     Unit *unit;
  1476.     WindowPtr frontwin;
  1477.  
  1478.     frontwin = FrontWindow();
  1479.     frontmap = map_from_window(frontwin);
  1480.     frontlist = list_from_window(frontwin);
  1481.     frontcloseup = unit_closeup_from_window(frontwin);
  1482.     menus_useful = (gamedefined && ((!beforestart && !endofgame) || (gameinited && dside->designer)));
  1483.     /* Certain menus need to be built after the game is running. */
  1484.     if (menus_useful) {
  1485.         build_material_type_menu();
  1486.         build_side_menu();
  1487.         build_ai_type_menu();
  1488.     }
  1489. #if 0
  1490.     if (is_da_window(FrontWindow())) {
  1491.         if ((menu = GetMHandle(mEdit)) != nil) {
  1492.         }
  1493.         return;
  1494.     }
  1495. #endif
  1496.     menu = GetMHandle(mApple);
  1497.     if (menu != nil) {
  1498.         adjust_menu_item(menu, miAppleInstructions, gamedefined);
  1499.     }
  1500.     menu = GetMHandle(mFile);
  1501.     if (menu != nil) {
  1502.         /* Availability of file menu items depends on whether we're in a game. */
  1503.         adjust_menu_item(menu, miFileNew, !gamedefined);
  1504.         adjust_menu_item(menu, miFileOpen, !gamedefined);
  1505.         adjust_menu_item(menu, miFileConnect, !gamedefined);
  1506.         adjust_menu_item(menu, miFileSave, menus_useful);
  1507.         adjust_menu_item(menu, miFileSaveAs, menus_useful);
  1508.         adjust_menu_item(menu, miFilePrintWindow, (frontmap != NULL || frontlist != NULL));
  1509.         adjust_menu_item(menu, miFileResign, menus_useful && dside->ingame);
  1510.     }
  1511.     menu = GetMHandle(mEdit);
  1512.     if (menu != nil) {
  1513.         /* Edit menu is always available, but most items may be disabled. */
  1514.         /* (should do the other items also) */
  1515.         adjust_menu_item(menu, miEditSelectAll, (frontmap != NULL || frontlist != NULL));
  1516.         if (menus_useful) {
  1517. #ifdef DESIGNERS
  1518.             CheckItem(menu, miEditDesign, dside->designer);
  1519. #else
  1520.             DisableItem(menu, miEditDesign);
  1521. #endif /* DESIGNERS */
  1522.         }
  1523.     }
  1524.     menu = GetMHandle(mFind);
  1525.     if (menu != nil) {
  1526.         if (gameinited) {
  1527.             EnableItem(menu, 0);
  1528.             adjust_menu_item(menu, miFindPrevious, menus_useful);
  1529.             adjust_menu_item(menu, miFindNext, menus_useful);
  1530.             adjust_menu_item(menu, miFindLocation, menus_useful);
  1531.             adjust_menu_item(menu, miFindUnitByName, TRUE);
  1532.             adjust_menu_item(menu, miFindSelected, (frontmap != NULL || frontlist != NULL || frontcloseup != NULL || constructionwin == frontwin));
  1533.         } else {
  1534.             /* We're not even in a game yet, turn entire menu off. */
  1535.             DisableItem(menu, 0);
  1536.         }
  1537.     }
  1538.     menu = GetMHandle(mPlay);
  1539.     if (menu != nil) {
  1540.         if (gameinited) {
  1541.             EnableItem(menu, 0);
  1542.             /* Disable everything first, then selectively re-enable. */
  1543.             DisableItem(menu, miPlayCloseup);
  1544.             DisableItem(menu, miPlayMove);
  1545.             DisableItem(menu, miPlayPatrol);
  1546.             DisableItem(menu, miPlayReturn);
  1547.             DisableItem(menu, miPlayWake);
  1548.             DisableItem(menu, miPlaySleep);
  1549.             DisableItem(menu, miPlayDoneMoving);
  1550.             DisableItem(menu, miPlayBuild);
  1551.             DisableItem(menu, miPlayRepair);
  1552.             DisableItem(menu, miPlayAttack);
  1553.             DisableItem(menu, miPlayOverrun);
  1554.             DisableItem(menu, miPlayFire);
  1555.             DisableItem(menu, miPlayFireInto);
  1556.             DisableItem(menu, miPlayDetonate);
  1557.             DisableItem(menu, miPlayTake);
  1558.             DisableItem(menu, miPlayDrop);
  1559.             DisableItem(menu, miPlayGive);
  1560.             DisableItem(menu, miPlayDisband);
  1561.             DisableItem(menu, miPlayRename);
  1562.             /* Note that command enabling is accumulative for all units. */
  1563.             if (frontmap != NULL) {
  1564.                 for (i = 0; i < frontmap->numselections; ++i) {
  1565.                     if ((unit = frontmap->selections[i]) != NULL) {
  1566.                         enable_commands_for_unit(menu, unit);
  1567.                     }
  1568.                 }
  1569.             } else if (frontlist != NULL) {
  1570.                 if ((unit = (Unit *) selected_unit_in_list(frontlist)) != NULL) {
  1571.                     enable_commands_for_unit(menu, unit);
  1572.                 }
  1573.             } else if (frontcloseup != NULL) {
  1574.                 if ((unit = frontcloseup->unit) != NULL) {
  1575.                     enable_commands_for_unit(menu, unit);
  1576.                 }
  1577.             }
  1578.         } else {
  1579.             /* We're not even in a valid game state yet, turn entire menu off. */
  1580.             DisableItem(menu, 0);
  1581.         }
  1582.     }
  1583.     menu = GetMHandle(mSide);
  1584.     if (menu != nil) {
  1585.         if (menus_useful) {
  1586.             EnableItem(menu, 0);
  1587.             CheckItem(menu, miSideMoveOnClick,
  1588.                       (frontmap ? frontmap->moveonclick : defaultmoveonclick));
  1589.             CheckItem(menu, miSideAutoSelect,
  1590.                       (frontmap ? frontmap->autoselect : defaultautoselect));
  1591.             CheckItem(menu, miSideAutoFinish, dside->autofinish);
  1592.             CheckItem(menu, miSideSound, playsounds);
  1593.             if (dside->nameslocked) {
  1594.                 DisableItem(menu, miSideRename);
  1595.             } else {
  1596.                 EnableItem(menu, miSideRename);
  1597.             }
  1598.         } else {
  1599.             /* We're not even in a game yet, turn entire menu off. */
  1600.             DisableItem(menu, 0);
  1601.         }
  1602.     }
  1603.     menu = GetMHandle(mWindows);
  1604.     if (menu != nil) {
  1605.         if (gameinited) {
  1606.             EnableItem(menu, 0);
  1607.             /* Every item is always enabled. (should be, anyway) */
  1608.             CheckItem(menu, miWindowsGame,
  1609.                 (gamewin && ((WindowPeek) gamewin)->visible));
  1610.             CheckItem(menu, miWindowsHistory,
  1611.                 (historywin && ((WindowPeek) historywin)->visible));
  1612.             if (any_construction_possible()) {
  1613.                 EnableItem(menu, miWindowsConstruction);
  1614.                 CheckItem(menu, miWindowsConstruction,
  1615.                     (constructionwin && ((WindowPeek) constructionwin)->visible));
  1616.             } else {
  1617.                 DisableItem(menu, miWindowsConstruction);
  1618.             }
  1619.             numwins = CountMItems(menu) - miWindowsFirst;
  1620.             for (i = 0; i < numwins; ++i) {
  1621.                 CheckItem(menu, i + miWindowsFirst, (winmenuwins[i] == frontwin));
  1622.             }
  1623.         } else {
  1624.             /* We're not even in a game yet, turn entire menu off. */
  1625.             DisableItem(menu, 0);
  1626.         }
  1627.     }
  1628.     /* If a map window is frontmost, install and adjust the map view menu. */
  1629.     if (frontmap != NULL) {
  1630.         /* Delete the list view menu if that's what's installed currently. */
  1631.         menu = GetMHandle(mViewList);
  1632.         if (menu != nil)
  1633.           DeleteMenu(mViewList);
  1634.         /* Make sure the map view menu is installed (is always at the end). */
  1635.         InsertMenu(mapviewmenu, 0);
  1636.         menu = GetMHandle(mViewMap);
  1637.         if (menu != nil) {
  1638.             EnableItem(menu, 0);
  1639.             if (frontmap->vp->power == 0) {
  1640.                 DisableItem(menu, miViewFarther);
  1641.             } else {
  1642.                 EnableItem(menu, miViewFarther);
  1643.             }
  1644.             if (frontmap->vp->power == NUMPOWERS-1) {
  1645.                 DisableItem(menu, miViewCloser);
  1646.             } else {
  1647.                 EnableItem(menu, miViewCloser);
  1648.             }
  1649.             EnableItem(menu, miViewGrid);
  1650.             CheckItem(menu, miViewGrid, frontmap->drawgrid);
  1651.             EnableItem(menu, miViewTopline);
  1652.             CheckItem(menu, miViewTopline, (frontmap->toph > 0));
  1653.             EnableItem(menu, miViewNames);
  1654.             CheckItem(menu, miViewNames, frontmap->drawnames);
  1655.             if (people_sides_defined()) {
  1656.                 EnableItem(menu, miViewPeople);
  1657.                 CheckItem(menu, miViewPeople, frontmap->drawpeople);
  1658.             } else {
  1659.                 DisableItem(menu, miViewPeople);
  1660.             }
  1661.             if (elevations_defined()) {
  1662.                 EnableItem(menu, miViewElevations);
  1663.                 CheckItem(menu, miViewElevations, frontmap->drawelevations);
  1664.             } else {
  1665.                 DisableItem(menu, miViewElevations);
  1666.             }
  1667.             if (1 /* any weather defined */) {
  1668.                 EnableItem(menu, miViewWeather);
  1669.             } else {
  1670.                 DisableItem(menu, miViewWeather);
  1671.             }
  1672.             if (nummtypes > 0) {
  1673.                 EnableItem(menu, miViewMaterials);
  1674.                 /* (should do checkmark if anything in submenu is on) */
  1675.             } else {
  1676.                 DisableItem(menu, miViewMaterials);
  1677.             }
  1678.             if (numbordtypes + numconntypes + numcoattypes > 0) {
  1679.                 EnableItem(menu, miViewTerrain);
  1680.             } else {
  1681.                 DisableItem(menu, miViewTerrain);
  1682.             }
  1683.             if (world.daylength != 1) {
  1684.                 EnableItem(menu, miViewDaylight);
  1685.                 CheckItem(menu, miViewDaylight, frontmap->drawlighting);
  1686.             } else {
  1687.                 DisableItem(menu, miViewDaylight);
  1688.             }
  1689.             if (dside->coverage) {
  1690.                 EnableItem(menu, miViewCoverage);
  1691.                 CheckItem(menu, miViewCoverage, frontmap->drawcover);
  1692.             } else {
  1693.                 DisableItem(menu, miViewCoverage);
  1694.             }
  1695.             if (nummaps > 1) {
  1696.                 EnableItem(menu, miViewOtherMaps);
  1697.                 CheckItem(menu, miViewOtherMaps, frontmap->drawothermaps);
  1698.             } else {
  1699.                 DisableItem(menu, miViewOtherMaps);
  1700.             }
  1701.             menu = GetMHandle(mViewWeather);
  1702.             if (menu != nil) {
  1703.                 EnableItem(menu, 0);
  1704.                 if (temperatures_defined()) {
  1705.                     EnableItem(menu, miWeatherTemperature);
  1706.                     CheckItem(menu, miWeatherTemperature, frontmap->drawtemperature);
  1707.                 } else {
  1708.                     DisableItem(menu, miWeatherTemperature);
  1709.                 }
  1710.                 if (winds_defined()) {
  1711.                     EnableItem(menu, miWeatherWinds);
  1712.                     CheckItem(menu, miWeatherWinds, frontmap->drawwinds);
  1713.                 } else {
  1714.                     DisableItem(menu, miWeatherWinds);
  1715.                 }
  1716.                 if (clouds_defined()) {
  1717.                     EnableItem(menu, miWeatherClouds);
  1718.                     CheckItem(menu, miWeatherClouds, frontmap->drawclouds);
  1719.                 } else {
  1720.                     DisableItem(menu, miWeatherClouds);
  1721.                 }
  1722.                 /* should define what this means */
  1723.                 DisableItem(menu, miWeatherStorms);
  1724. /*                CheckItem(menu, miWeatherStorms, frontmap->drawstorms); */
  1725.             }
  1726.         }
  1727.     } else if (frontlist != NULL) {
  1728.         /* Do the list view menu similarly. */
  1729.         menu = GetMHandle(mViewMap);
  1730.         if (menu != nil)
  1731.           DeleteMenu(mViewMap);
  1732.         /* Make sure the menu is actually installed (is always at the end). */
  1733.         InsertMenu(listviewmenu, 0);
  1734.         menu = GetMHandle(mViewList);
  1735.         if (menu != nil) {
  1736.             EnableItem(menu, 0);
  1737.             if (1 /* at least one unit in list */) {
  1738.                 EnableItem(menu, miViewByType);
  1739.                 CheckItem(menu, miViewByType, (frontlist->mainsortmi == miViewByType));
  1740.                 EnableItem(menu, miViewByName);
  1741.                 CheckItem(menu, miViewByName, (frontlist->mainsortmi == miViewByName));
  1742.                 EnableItem(menu, miViewBySide);
  1743.                 CheckItem(menu, miViewBySide, (frontlist->mainsortmi == miViewBySide));
  1744.                 EnableItem(menu, miViewByActOrder);
  1745.                 CheckItem(menu, miViewByActOrder, (frontlist->mainsortmi == miViewByActOrder));
  1746.                 EnableItem(menu, miViewByLocation);
  1747.                 CheckItem(menu, miViewByLocation, (frontlist->mainsortmi == miViewByLocation));
  1748.                 /* should mark the secondary sort? */
  1749.                 EnableItem(menu, miViewWithTransport);
  1750.                 DisableItem(menu, miViewWithCommander);
  1751.                 EnableItem(menu, miViewIconSize);
  1752.                 CheckItem(menu, miViewIconSize, frontlist->largeicons);
  1753.             } else {
  1754.                 DisableItem(menu, miViewByType);
  1755.                 DisableItem(menu, miViewByName);
  1756.                 DisableItem(menu, miViewBySide);
  1757.                 DisableItem(menu, miViewByActOrder);
  1758.                 DisableItem(menu, miViewByLocation);
  1759.                 DisableItem(menu, miViewWithTransport);
  1760.                 DisableItem(menu, miViewWithCommander);
  1761.                 DisableItem(menu, miViewIconSize);
  1762.             }
  1763.         }
  1764.     } else {
  1765.         /* For any other window, disable any or all of the view menus, as needed. */
  1766.         menu = GetMHandle(mViewList);
  1767.         if (menu != nil)
  1768.           DisableItem(menu, 0);
  1769.         menu = GetMHandle(mViewMap);
  1770.         if (menu != nil)
  1771.           DisableItem(menu, 0);
  1772.     }
  1773.     menu = GetMHandle(mMagnifications);
  1774.     if (menu != nil) {
  1775.         /* Always on. */
  1776.         EnableItem(menu, 0);
  1777.         if (frontmap != NULL) {
  1778.             for (i = 0; i < NUMPOWERS; ++i) {
  1779.                 CheckItem(menu, i + 1, (i == frontmap->vp->power));
  1780.             }
  1781.         }
  1782.     }
  1783.     menu = GetMHandle(mMaterialTypes);
  1784.     if (menu != nil) {
  1785.         /* Always on, if any material types defined. */
  1786.         if (nummtypes > 0) {
  1787.             EnableItem(menu, 0);
  1788.         } else {
  1789.             DisableItem(menu, 0);
  1790.         }
  1791.         if (frontmap != NULL) {
  1792.             for_all_material_types(m) {
  1793.                 if (any_cell_materials_defined() && cell_material_defined(m)) {
  1794.                     EnableItem(menu, m + 1);
  1795.                     CheckItem(menu, m + 1, frontmap->drawmaterials[m]);
  1796.                 } else {
  1797.                     CheckItem(menu, i, FALSE);
  1798.                     DisableItem(menu, m + 1);
  1799.                 }
  1800.             }
  1801.         }
  1802.     }
  1803.     menu = GetMHandle(mOptTerrainTypes);
  1804.     if (menu != nil) {
  1805.         /* Always on, if any material types defined. */
  1806.         if (1) {
  1807.             EnableItem(menu, 0);
  1808.         } else {
  1809.             DisableItem(menu, 0);
  1810.         }
  1811.         if (frontmap != NULL) {
  1812.             numitems = CountMItems(optterrmenu);
  1813.             for (i = 1; i <= numitems; ++i) {
  1814.                 t = frontmap->auxterraintypes[i];
  1815.                 if (any_aux_terrain_defined() && aux_terrain_defined(t)) {
  1816.                     EnableItem(menu, i);
  1817.                     CheckItem(menu, i, frontmap->drawauxterrain[t]);
  1818.                 } else {
  1819.                     CheckItem(menu, i, FALSE);
  1820.                     DisableItem(menu, i);
  1821.                 }
  1822.             }
  1823.         }
  1824.     }
  1825.     menu = GetMHandle(mAITypes);
  1826.     if (menu != nil) {
  1827.         /* Always on. */
  1828.         EnableItem(menu, 0);
  1829.         CheckItem(menu, 1, (!side_has_ai(dside)));
  1830.         CheckItem(menu, 2, (side_has_ai(dside)));
  1831.     }
  1832.     /* Everything has been tweaked, redraw the menu bar. */
  1833.     DrawMenuBar();
  1834. }
  1835.  
  1836. /* Tweak the command menu according to what the unit can do. */
  1837. /* (some of these should have the menu text tweaked also, terms weird sometimes) */
  1838.  
  1839. void
  1840. enable_commands_for_unit(MenuHandle menu, Unit *unit)
  1841. {
  1842.     int u = unit->type;
  1843.  
  1844.     /* If we can select the unit at all, we can always get a closeup of it. */
  1845.     EnableItem(menu, miPlayCloseup);
  1846.     /* (how to do checkmarks if multiple units selected? use '-' as per HIG) */
  1847.     CheckItem(menu, miPlayCloseup, (find_unit_closeup(unit) != NULL));
  1848.     /* If we don't actually have any control over the unit, or the game is over,
  1849.        nothing more to do. */
  1850.     if (!side_controls_unit(dside, unit) || endofgame)
  1851.       return;
  1852.     if (can_move_at_all(unit)) {
  1853.         EnableItem(menu, miPlayMove);
  1854.         EnableItem(menu, miPlayPatrol);
  1855.         /* also check for places to return to? */
  1856.         EnableItem(menu, miPlayReturn);
  1857.     }
  1858.     if (unit->plan) {
  1859.         EnableItem(menu, miPlayWake);
  1860.         CheckItem(menu, miPlayWake, !unit->plan->asleep);
  1861.         EnableItem(menu, miPlaySleep);
  1862.         CheckItem(menu, miPlaySleep, unit->plan->asleep);
  1863.         EnableItem(menu, miPlayDoneMoving);
  1864.         CheckItem(menu, miPlayDoneMoving, unit->plan->reserve);
  1865.     }
  1866.     if (can_create(unit) || can_complete(unit) || can_research(unit)) {
  1867.         EnableItem(menu, miPlayBuild);
  1868.     }
  1869.     if (can_repair(unit)) {
  1870.         EnableItem(menu, miPlayRepair);
  1871.     }
  1872.     if (can_attack(unit)) {
  1873.         EnableItem(menu, miPlayAttack);
  1874.         EnableItem(menu, miPlayOverrun);
  1875.     }
  1876.     if (can_fire(unit)) {
  1877.         EnableItem(menu, miPlayFire);
  1878.         EnableItem(menu, miPlayFireInto);
  1879.     }
  1880.     if (can_detonate(unit)) {
  1881.         EnableItem(menu, miPlayDetonate);
  1882.     }
  1883.     if (1 /*dside->designer*/) {
  1884.         EnableItem(menu, miPlayGive);
  1885.     }
  1886.     if (can_disband_at_all(dside, unit)) {
  1887.         EnableItem(menu, miPlayDisband);
  1888.     }
  1889.     if (1 /* !unitnameslocked */) {
  1890.         EnableItem(menu, miPlayRename);
  1891.     }
  1892. }
  1893.