home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / mac / maccmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  29.0 KB  |  1,600 lines  |  [TEXT/R*ch]

  1. /* Commands for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995, 1996 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. extern void update_debugging PARAMS ((void));
  11. extern void toggle_debugging PARAMS ((int *flagp));
  12. extern int can_build_or_help PARAMS ((Unit *unit));
  13. extern int can_produce PARAMS ((Unit *unit));
  14. extern Task *create_produce_task PARAMS ((int m, int n));
  15. extern void push_produce_task PARAMS ((Unit *unit, int m, int n));
  16. /* Only defined if ansi */
  17. extern void vnotify(Side *side, char *fmt, va_list ap);
  18. #include "print.h"
  19. #include "macconq.h"
  20. extern void enable_command(void);
  21. extern void set_construction_run_length(int len);
  22.  
  23. /* Define in order to get profiling controls. */
  24. #undef PROFILING
  25.  
  26. #ifdef THINK_C
  27. #include <profile.h>
  28. #endif
  29.  
  30. #ifdef PROFILING
  31. extern int _trace;
  32. #endif
  33.  
  34. extern WindowPtr playersetupwin;
  35.  
  36. extern int forcedtoresign;
  37.  
  38. extern int modal_construction;
  39.  
  40. extern WindowPtr window_behind_construction;
  41.  
  42. int position_set_modally;
  43.  
  44. Point modal_point;
  45.  
  46. Map *modal_map;
  47.  
  48. #ifdef DESIGNERS
  49. #define side_may_select(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
  50. #define valid_selection(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
  51. #else
  52. #define side_may_select(unit) (in_play(unit) && ((unit)->side == dside))
  53. #define valid_selection(unit) (in_play(unit) && ((unit)->side == dside))
  54. #endif
  55.  
  56. extern char *cursavename;
  57.  
  58. #undef DEF_CMD
  59. #define DEF_CMD(letter,name,args,FN,help) extern void FN(void);
  60.  
  61. #include "cmd.def"
  62.  
  63. #include "maccmd.def"
  64.  
  65. /* Local function declarations. */
  66.  
  67. static int do_one_add_terrain(Unit *unit);
  68. static int do_one_ai_control(Unit *unit);
  69. static void unit_do_build_2(Unit *unit);
  70. extern int do_one_clear_plan(Unit *unit);
  71. static int do_one_delay(Unit *unit);
  72. extern int do_one_detach(Unit *unit);
  73. extern int do_one_detonate(Unit *unit);
  74. extern int do_one_dir_move(Unit *unit);
  75. extern int do_one_dir_multiple_move(Unit *unit);
  76. extern int do_one_disband(Unit *unit);
  77. extern int do_one_disembark(Unit *unit);
  78. extern int do_one_embark(Unit *unit);
  79. extern int do_one_give(Unit *unit);
  80. extern int do_one_give_unit(Unit *unit);
  81. static int do_one_occupant(Unit *unit);
  82. static int do_one_remove_terrain(Unit *unit);
  83. static int do_one_reserve(Unit *unit);
  84. extern int do_one_return(Unit *unit);
  85. extern int do_one_set_name(Unit *unit);
  86. static int do_one_asleep(Unit *unit);
  87. extern int do_one_take(Unit *unit);
  88.  
  89. static void resign_the_game(int forced);
  90.  
  91. static void cmd_error(Side *side, char *fmt, ...);
  92.  
  93. /* Static (local) variables. */
  94.  
  95. static int tmpcmdarg;
  96. static int tmprecurse;
  97.  
  98. static int tmpcmdx, tmpcmdy, tmpcmddir;
  99.  
  100. /* This is the actual key typed, for use if several keyboard commands
  101.    share a single function. */
  102.  
  103. static char tmpkey;
  104.  
  105. /* Prefixed numeric argument to commands. */
  106.  
  107. static int prefixarg;
  108.  
  109. static int tmpdir;
  110.  
  111. static char *cmdargstr;
  112.  
  113. /* This flag is set to prevent running an "other" command when already
  114.    executing an "other" command. */
  115.  
  116. static int doingother = FALSE;
  117.  
  118. typedef struct cmdtab {
  119.     char fchar;                 /* character to match against */
  120.     char *name;                 /* full name of command */
  121.     void (*fn)(void);           /* pointer to command's function */
  122.     char *help;                 /* short documentation string */
  123. } CmdTab;
  124.  
  125. #define C(c) ((c)-0x40)
  126.  
  127. #undef DEF_CMD
  128. #define DEF_CMD(LETTER,NAME,args,FN,HELP) { LETTER, NAME, FN, HELP },
  129.  
  130. /* The generic command table. */
  131.  
  132. CmdTab commands[] = {
  133.  
  134. #include "maccmd.def"
  135.  
  136. #include "cmd.def"
  137.  
  138.   { 0, NULL, NULL, NULL }
  139. };
  140.  
  141. /* The Mac-specific command table. */
  142.  
  143. CmdTab mac_commands[] = {
  144.  
  145. #include "maccmd.def"
  146.  
  147.   { 0, NULL, NULL, NULL }
  148. };
  149.  
  150. /* Given a character, find a command for it and execute. */
  151.  
  152. void
  153. do_keyboard_command(int key)
  154. {
  155.     CmdTab *cmd;
  156.     void (*fn)(void);
  157.  
  158.     DGprintf("Typed '%c' (0x%x)\n", key, key);
  159.     if (between('0', key, '9')) {
  160.         /* Add a decimal digit to the prefix argument. */
  161.         if (prefixarg < 0)
  162.           prefixarg = 0;
  163.         prefixarg += prefixarg * 10 + (key - '0');
  164.         /* (should add some sort of feedback) */
  165.     } else {
  166.         /* Look through the generic command table. */
  167.         for (cmd = commands; cmd->name != NULL; ++cmd) {
  168.             if (key == cmd->fchar) {
  169.                 if ((fn = cmd->fn) == NULL) {
  170.                     run_warning("no command function for %s (0x%x)?", cmd->name, key);
  171.                     return;
  172.                 }
  173.                 tmpkey = key;
  174.                 (*fn)();
  175.                 /* Reset the prefix argument. */
  176.                 prefixarg = -1;
  177.                 return;
  178.             }
  179.         }
  180.     }
  181. }
  182.  
  183. void
  184. execute_named_command(char *cmdstr)
  185. {
  186.     char *cmdname;
  187.     CmdTab *cmd;
  188.     void (*fn)(void);
  189.  
  190.     parse_long_name_command(cmdstr, &cmdname, &cmdargstr, copy_string(cmdstr)); 
  191.     if (empty_string(cmdname)) {
  192.         notify(dside, "No command name.");
  193.         beep();
  194.         return;
  195.     }
  196.     for (cmd = commands; cmd->name != NULL; ++cmd) {
  197.         if (strcmp(cmdname, cmd->name) == 0) {
  198.             fn = cmd->fn;
  199.             if (fn == NULL) {
  200.                 run_warning("no command function for %s?", cmd->name);
  201.                 return;
  202.             }
  203.             /* Use the command's char as the apparent key. */
  204.             tmpkey = cmd->fchar;
  205.             (*fn)();
  206.             /* Reset the prefix argument. */
  207.             prefixarg = -1;
  208.             return;
  209.         }
  210.     }
  211.     notify(dside, "Command \"%s\" not recognized.", cmdname);
  212.     beep();
  213. }
  214.  
  215. void
  216. describe_commands(int arg, char *key, char *buf)
  217. {
  218.     describe_command_table(arg, key, buf, commands);
  219.     /* (should split out Mac-specific commands??) */
  220. }
  221.  
  222. void
  223. describe_command_table(int arg, char *key, char *buf, CmdTab *cmdtab)
  224. {
  225.     CmdTab *cmd;
  226.  
  227.     strcat(buf, "Single-key commands:\n\n");
  228.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  229.         describe_command(cmd->fchar, cmd->name, cmd->help, TRUE, buf);
  230.     }
  231.     strcat(buf, "\nLong name commands:\n\n");
  232.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  233.         describe_command (cmd->fchar, cmd->name, cmd->help, FALSE, buf);
  234.     }
  235. }
  236.  
  237. int
  238. get_a_position(Map **mapp, int *xp, int *yp, int *dirp)
  239. {
  240.     Point at;
  241.  
  242.     if (position_set_modally) {
  243.         position_set_modally = FALSE;
  244.         *mapp = modal_map;
  245.         return m_nearest_boundary(*mapp, modal_point.h, modal_point.v, xp, yp, dirp);
  246.     } else if ((*mapp = map_from_window(FrontWindow())) != NULL) {
  247.         GetMouse(&at);
  248.         return m_nearest_boundary(*mapp, at.h, at.v, xp, yp, dirp);
  249.     }
  250.     return FALSE;
  251. }
  252.  
  253. int
  254. get_a_unit(Map **mapp, Unit **unitp)
  255. {
  256.     Point at;
  257.  
  258.     if (position_set_modally) {
  259.         position_set_modally = FALSE;
  260.         *mapp = modal_map;
  261.         return m_nearest_unit(*mapp, modal_point.h, modal_point.v, unitp);
  262.     } else if ((*mapp = map_from_window(FrontWindow())) != NULL) {
  263.         GetMouse(&at);
  264.         return m_nearest_unit(*mapp, at.h, at.v, unitp);
  265.     }
  266.     return FALSE;
  267. }
  268.  
  269. /* Start of alphabetized commands. */
  270.  
  271. void
  272. do_add_player()
  273. {
  274.     request_additional_side(cmdargstr);
  275. }
  276.  
  277. void
  278. do_add_terrain()
  279. {
  280.     int x, y, dir;
  281.     Map *map;
  282.  
  283.     if (get_a_position(&map, &x, &y, &dir)) {
  284.         tmpcmdx = x;  tmpcmdy = y;  tmpcmddir = dir;
  285.         apply_to_all_selected(do_one_add_terrain, TRUE);
  286.         return;
  287.     }
  288.     beep();
  289. }
  290.  
  291. static int
  292. do_one_add_terrain(Unit *unit)
  293. {
  294.     int u, t, t1, x, y, dir, tfirst = -1, numtypes, possibles[MAXTTYPES];
  295.  
  296.     u = unit->type;
  297.     numtypes = 0;
  298.     for_all_terrain_types(t) {
  299.         if (ut_acp_to_add_terrain(u, t) > 0) {
  300.             possibles[numtypes++] = t;
  301.         }
  302.     }
  303.     if (numtypes == 0) {
  304.         return FALSE;
  305.     } else if (numtypes == 1) {
  306.         t1 = possibles[0];
  307.     } else {
  308.         /* should have better way to choose type */
  309.         if (between(0, prefixarg, numtypes - 1))
  310.           t1 = possibles[prefixarg];
  311.         else {
  312.             notify(dside, "Prefix should be 0 to %d", numtypes - 1); 
  313.             return FALSE;
  314.         }
  315.     }
  316.     /* (should put following in ui.c?) */
  317.     switch (t_subtype(t1)) {
  318.         case cellsubtype:
  319.             if (valid(check_alter_cell_action(unit, unit, tmpcmdx, tmpcmdy, t1))) {
  320.                 if (prep_alter_cell_action(unit, unit, tmpcmdx, tmpcmdy, t1))
  321.                   return TRUE;
  322.             }
  323.             break;
  324.         case bordersubtype:
  325.         case connectionsubtype:
  326.             if (distance(tmpcmdx, tmpcmdy, unit->x, unit->y) <= ut_alter_range(u, t1)) {
  327.                 x = tmpcmdx;  y = tmpcmdy;
  328.                 dir = tmpcmddir;
  329.             } else {
  330.                 x = unit->x;  y = unit->y;
  331.                 dir = approx_dir(tmpcmdx - unit->x, tmpcmdy - unit->y);
  332.             }
  333.             if (valid(check_add_terrain_action(unit, unit, x, y, dir, t1))) {
  334.                 if (prep_add_terrain_action(unit, unit, x, y, dir, t1))
  335.                   return TRUE;
  336.             }
  337.             break;
  338.         case coatingsubtype:
  339.             break;
  340.     }
  341.     return FALSE;
  342. }
  343.  
  344. void
  345. do_ai_side()
  346. {
  347.     if (side_has_ai(dside)) {
  348.         set_side_ai(dside, NULL);
  349.     } else {
  350.         set_side_ai(dside, "mplayer");
  351.     }
  352. }
  353.  
  354. void
  355. do_attack()
  356. {
  357.     do_attack_command();
  358. }
  359.  
  360. void
  361. do_auto()
  362. {
  363.     apply_to_all_selected(do_one_ai_control, TRUE);    
  364. }
  365.  
  366. static int
  367. do_one_ai_control(Unit *unit)
  368. {
  369.     int newval;
  370.  
  371.     if (unit->plan) {
  372.         if (prefixarg < 0)
  373.           newval = !unit->plan->aicontrol;
  374.         else if (prefixarg == 0)
  375.           newval = 0;
  376.         else
  377.           newval = 1;
  378.         set_unit_ai_control(dside, unit, newval, FALSE);
  379.         /* a hack */
  380.         unit->plan->waitingfortasks = !unit->plan->aicontrol;
  381.     }
  382.     return TRUE;
  383. }
  384.  
  385. void
  386. do_build()
  387. {
  388.     int i;
  389.     Map *map;  List *list;  UnitCloseup *closeup;
  390.     Unit *unit;
  391.  
  392.     map = map_from_window(FrontWindow());
  393.     if (map != NULL) {
  394.         for (i = 0; i < map->numselections; ++i) {
  395.             unit = map->selections[i];
  396.             if (unit != NULL && can_build_or_help(unit)) {
  397.                 unit_do_build_2(unit);
  398.                 return;
  399.             }
  400.         }
  401.         return;
  402.     }
  403.     list = list_from_window(FrontWindow());
  404.     if (list != NULL) {
  405.         unit = selected_unit_in_list(list);
  406.         if (unit != NULL && can_build_or_help(unit)) {
  407.             unit_do_build_2(unit);
  408.             return;
  409.         }
  410.         return;
  411.     }
  412.     closeup = unit_closeup_from_window(FrontWindow());
  413.     if (closeup != NULL) {
  414.         unit = closeup->unit;
  415.         if (unit != NULL && can_build_or_help(unit)) {
  416.             unit_do_build_2(unit);
  417.             return;
  418.         }
  419.         return;
  420.     }
  421.     /* No way to figure out the unit to be building with, so complain. */
  422.     beep();
  423. }
  424.  
  425. void
  426. unit_do_build_2(Unit *unit)
  427. {
  428.     extern int editedrunlength;
  429.  
  430.     modal_construction = TRUE;
  431.     window_behind_construction = FrontWindow();
  432.     if (prefixarg > 0)
  433.       set_construction_run_length(prefixarg);
  434.     if (prefixarg > 0)
  435.       editedrunlength = prefixarg;
  436.     else
  437.       editedrunlength = -1;
  438.     enable_construction();
  439.     select_unit_in_construction_window(unit);
  440.     select_type_in_construction_window(favored_type(unit));
  441. }
  442.  
  443. /* Create and/or bring up the construction planning window. */
  444.  
  445. void
  446. enable_construction()
  447. {
  448.     window_behind_construction = FrontWindow();
  449.     if (constructionwin == nil) {
  450.         create_construction_window();
  451.     }
  452.     if (constructionwin != nil) {
  453.         reinit_construction_lists();
  454.         ShowWindow(constructionwin);
  455.         SelectWindow(constructionwin);
  456.     }
  457. }
  458.  
  459. int
  460. do_one_clear_plan(Unit *unit)
  461. {
  462.     if (unit->plan) {
  463.         set_unit_plan_type(dside, unit, PLAN_NONE);
  464.         return TRUE;
  465.     }
  466.     return FALSE;
  467. }
  468.  
  469. void
  470. do_clear_plan()
  471. {
  472.     apply_to_all_selected(do_one_clear_plan, TRUE);    
  473. }
  474.  
  475. void
  476. do_copying()
  477. {
  478.     help_dialog(copying_help_node);
  479. }
  480.  
  481. void
  482. do_delay()
  483. {
  484.     apply_to_all_selected(do_one_delay, TRUE);
  485. }
  486.  
  487. int
  488. do_one_delay(Unit *unit)
  489. {
  490.     if (unit->plan) {
  491.         delay_unit(unit, TRUE);
  492.         return TRUE;
  493.     }
  494.     return FALSE;
  495. }
  496.  
  497. void
  498. do_detach()
  499. {
  500.     apply_to_all_selected(do_one_detach, TRUE);
  501. }
  502.  
  503. int
  504. do_one_detach(Unit *unit)
  505. {
  506.     if (!completed(unit)) {
  507.         return FALSE;
  508.     } else if (valid(check_transfer_part_action(unit, unit, unit->hp / 2, NULL))) {
  509.         prep_transfer_part_action(unit, unit, unit->hp / 2, NULL);
  510.         return TRUE;
  511.     } else {
  512.         /* try to find a nearby unit to do it */
  513.     }
  514.     return FALSE;
  515. }
  516.  
  517. void
  518. do_detonate()
  519. {
  520.     do_detonate_command();
  521. }
  522.  
  523. /* Command all selected mobile units to move in a given direction. */
  524.  
  525. /* The function that gets called on each selected unit. */
  526.  
  527. int
  528. do_one_dir_move(Unit *unit)
  529. {
  530.     int nx, ny;
  531.  
  532.     if (mobile(unit->type)) {
  533.         if (point_in_dir(unit->x, unit->y, tmpdir, &nx, &ny)) {
  534.             return advance_into_cell(dside, unit, nx, ny, unit_at(nx, ny));
  535.         }
  536.         return FALSE;
  537.     }
  538.     return FALSE;
  539. }
  540.  
  541. /* The command function proper. */
  542.  
  543. void
  544. do_dir()
  545. {
  546.     int ndirs, dir1, dir2, modif;
  547.     Map *map;
  548.  
  549.     map = map_from_window(FrontWindow());
  550.     if (map != NULL) {
  551.         ndirs = char_to_dir(tmpkey, &dir1, &dir2, &modif);
  552.         if (ndirs >= 1) {
  553.             tmpdir = dir1;
  554.         } else {
  555.             beep();
  556.             return;
  557.         }
  558.         apply_to_all_selected(do_one_dir_move, TRUE);
  559.     }
  560. }
  561.  
  562. /* Command all selected mobile units to move in a given direction. */
  563.  
  564. /* The function that gets called on each selected unit. */
  565.  
  566. int
  567. do_one_dir_multiple_move(Unit *unit)
  568. {
  569.     if (mobile(unit->type)) {
  570.         set_move_dir_task(unit, tmpdir, (prefixarg <= 0 ? 9999 : prefixarg));
  571.         return TRUE;
  572.     }
  573.     return FALSE;
  574. }
  575.  
  576. /* The command function proper. */
  577.  
  578. void
  579. do_dir_multiple()
  580. {
  581.     int ndirs, dir1, dir2, modif;
  582.     Map *map;
  583.  
  584.     map = map_from_window(FrontWindow());
  585.     if (map != NULL) {
  586.         ndirs = char_to_dir(tmpkey, &dir1, &dir2, &modif);
  587.         if (ndirs >= 1) {
  588.             tmpdir = dir1;
  589.         } else {
  590.             beep();
  591.             return;
  592.         }
  593.         apply_to_all_selected(do_one_dir_multiple_move, TRUE);
  594.     }
  595. }
  596.  
  597. void
  598. do_disband()
  599. {
  600.     apply_to_all_selected(do_one_disband, TRUE);
  601. }
  602.  
  603. int
  604. do_one_disband(Unit *unit)
  605. {
  606.     return disband_unit(dside, unit);
  607. }
  608.  
  609. void
  610. do_disembark()
  611. {
  612.     apply_to_all_selected(do_one_disembark, TRUE);
  613. }
  614.  
  615. int
  616. do_one_disembark(Unit *unit)
  617. {
  618.     Unit *transport = unit->transport;
  619.  
  620.     if (transport == NULL)
  621.       return FALSE;
  622.     /* Try moving into the transport's transport, if there is one. */
  623.     if (transport->transport != NULL
  624.         && can_occupy(unit, transport->transport)) {
  625.         prep_enter_action(unit, unit, transport->transport);
  626.         /* (should be able to set up task if can't do action immediately) */
  627.         return TRUE;
  628.     }
  629.     /* Try moving into the open in the cell. */
  630.     if (!inside_area(unit->x, unit->y))
  631.       return FALSE;
  632.     if (can_occupy_cell(unit, unit->x, unit->y)
  633.         || can_occupy_conn(unit, unit->x, unit->y, unit->z)) {
  634.         prep_move_action(unit, unit, unit->x, unit->y, unit->z);
  635.         /* (should be able to set up task if can't do action immediately) */
  636.         return TRUE;
  637.     }
  638.     return FALSE;
  639. }
  640.  
  641. void
  642. do_distance()
  643. {
  644.     notify(dside, "Click, then drag to location to which you want the distance.");
  645.     query_position_modally(DISTANCE_MODAL);
  646. }
  647.  
  648. void
  649. do_distrust()
  650. {
  651.     Side *side2;
  652.  
  653.     if (cmdargstr) {
  654.         side2 = parse_side_spec(cmdargstr);
  655.         if (side2 != NULL && side2 != dside) {
  656.             set_trust(dside, side2, 0);
  657.             return;
  658.         } 
  659.     }
  660.     beep();
  661. }
  662.  
  663. void
  664. do_draw_willingness()
  665. {
  666.     if (prefixarg < 0)
  667.       prefixarg = 1;
  668.     set_willing_to_draw(dside, (prefixarg ? 1 : 0));
  669. }
  670.  
  671. void
  672. do_embark()
  673. {
  674.     apply_to_all_selected(do_one_embark, TRUE);
  675. }
  676.  
  677. int
  678. do_one_embark(Unit *unit)
  679. {
  680.     int x = unit->x, y = unit->y;
  681.     Unit *transport = unit->transport, *unit2, *unit3;
  682.  
  683.     /* Note that occupation tests check for unit == transport case,
  684.        so not necessary in the code below. */
  685.     if (transport == NULL) {
  686.         /* Unit is in the open. */
  687.         for_all_stack(x, y, unit2) {
  688.             if (unit2 != transport && can_occupy(unit, unit2)) {
  689.                 prep_enter_action(unit, unit, unit2);
  690.                 return TRUE;
  691.             }
  692.         }
  693.         for_all_stack(x, y, unit2) {
  694.             for_all_occupants(unit2, unit3) {
  695.                 if (unit3 != transport && can_occupy(unit, unit3)) {
  696.                     prep_enter_action(unit, unit, unit3);
  697.                     return TRUE;
  698.                 }
  699.             }
  700.         }
  701.     } else {
  702.         for_all_occupants(transport, unit2) {
  703.             if (unit2 != transport && can_occupy(unit, unit2)) {
  704.                 prep_enter_action(unit, unit, unit2);
  705.                 return TRUE;
  706.             }
  707.         }
  708.         if (transport->transport == NULL) {
  709.             for_all_stack(x, y, unit2) {
  710.                 if (unit2 != transport && can_occupy(unit, unit2)) {
  711.                     prep_enter_action(unit, unit, unit2);
  712.                     return TRUE;
  713.                 }
  714.             }
  715.             for_all_stack(x, y, unit2) {
  716.                 for_all_occupants(unit2, unit3) {
  717.                     if (unit3 != transport && can_occupy(unit, unit3)) {
  718.                         prep_enter_action(unit, unit, unit3);
  719.                         return TRUE;
  720.                     }
  721.                 }
  722.             }
  723.         } else {
  724.             for_all_occupants(transport->transport, unit2) {
  725.                 if (unit2 != transport && can_occupy(unit, unit2)) {
  726.                     prep_enter_action(unit, unit, unit2);
  727.                     return TRUE;
  728.                 }
  729.             }
  730.         }
  731.     }
  732.     return FALSE;
  733. }
  734.  
  735. void
  736. do_end_turn()
  737. {
  738.     /* <return> is also interpreted by dialogs, so special-case this, depending
  739.        on which window was in front. */
  740.     if (FrontWindow() == constructionwin) {
  741.         Point pt;
  742.         extern ControlHandle constructbutton;
  743.         
  744.         pt.h = (*constructbutton)->contrlRect.left + 8;
  745.         pt.v = (*constructbutton)->contrlRect.top + 8;
  746.         do_mouse_down_construction(pt, 0);
  747.     } else {
  748.         finish_turn(dside);
  749.     }
  750. }
  751.  
  752. void
  753. do_fire()
  754. {
  755.     do_fire_command();
  756. }
  757.  
  758. void
  759. do_fire_into()
  760. {
  761.     do_fire_into_command();
  762. }
  763.  
  764. void
  765. do_follow_action()
  766. {
  767.     Map *map;
  768.  
  769.     map = map_from_window(FrontWindow());
  770.     if (map != NULL) {
  771.         map->follow_action = !map->follow_action;
  772.     }
  773. }
  774.  
  775. void
  776. do_force_global_replan()
  777. {
  778.     force_global_replan(dside);
  779. }
  780.  
  781. void
  782. do_give()
  783. {
  784.     /* (should use argument) */
  785.     apply_to_all_selected(do_one_give, TRUE);
  786. }
  787.  
  788. void
  789. do_give_unit()
  790. {
  791.     int sn = 0;
  792.     Side *side;
  793.  
  794.     side = side_n(sn);
  795.     apply_to_all_selected(do_one_give_unit, TRUE);
  796. }
  797.  
  798. void
  799. do_help()
  800. {
  801.     /* Bring up the help window at wherever it was, if already
  802.        created, otherwise will start at topics node. */
  803.     help_dialog(NULL);
  804. }
  805.  
  806. void
  807. do_message()
  808. {
  809.     message_dialog();
  810. }
  811.  
  812. /* Dialog for the input of a textual message. */
  813.  
  814. /* (should add way to specify which sides to receive this) */
  815.  
  816. void
  817. message_dialog()
  818. {
  819.     short done = FALSE, ditem;
  820.     char *msg = NULL;
  821.     DialogPtr win;
  822.     short itemtype;  Handle itemhandle;  Rect itemrect;
  823.  
  824.     win = GetNewDialog(dMessage, NULL, (DialogPtr) -1L);
  825.     ShowWindow(win);
  826.     while (!done) {
  827.         draw_default_button(win, diMessageOK);
  828.         SetCursor(&QD(arrow));
  829.         ModalDialog(NULL, &ditem);
  830.         switch (ditem) {
  831.             case diMessageOK:
  832.                 GetDItem(win, diMessageText, &itemtype, &itemhandle, &itemrect);
  833.                 msg = get_string_from_item(itemhandle);
  834.                 /* Fall into next case. */
  835.             case diMessageCancel:
  836.                 done = TRUE;
  837.                 break;
  838.         }
  839.     }
  840.     /* Close down the dialog (*before* executing any command). */
  841.     DisposDialog(win);
  842.     /* Now send the message (if it wasn't cancelled) */
  843.     if (msg != NULL) {
  844.         send_message(dside, ALLSIDES, msg);
  845.     }
  846. }
  847.  
  848. void
  849. do_move_to()
  850. {
  851.     notify(dside, "Click on location to which you want to move.");
  852.     query_position_modally(MOVE_TO_MODAL);
  853. }
  854.  
  855. extern int do_one_move_to(Unit *unit);
  856.  
  857. int
  858. do_move_to_command()
  859. {
  860.     int x, y, dir;
  861.     Map *map;
  862.  
  863.     if (get_a_position(&map, &x, &y, &dir)) {
  864.         tmpcmdx = x;  tmpcmdy = y;
  865.         apply_to_all_selected(do_one_move_to, TRUE);
  866.         return TRUE;
  867.     }
  868.     return FALSE;
  869. }
  870.  
  871. int
  872. do_one_move_to(Unit *unit)
  873. {
  874. #ifdef DESIGNERS
  875.     if (dside->designer) {
  876.         designer_teleport(unit, tmpcmdx, tmpcmdy, NULL);
  877.         return TRUE;
  878.     }
  879. #endif /* DESIGNERS */
  880.     set_move_to_task(unit, tmpcmdx, tmpcmdy);
  881.     return TRUE;
  882. }
  883.  
  884. int
  885. do_one_set_name(Unit *unit)
  886. {
  887.     return unit_rename_dialog(unit);
  888. }
  889.  
  890. void
  891. do_name()
  892. {
  893.     apply_to_all_selected(do_one_set_name, TRUE);
  894. }
  895.  
  896. int
  897. do_one_occupant(Unit *unit)
  898. {
  899.     Unit *nextocc;
  900.     Map *map;
  901.  
  902.     nextocc = find_next_occupant(unit);
  903.     if (nextocc != unit) {
  904.         map = map_from_window(FrontWindow());
  905.         if (map != NULL) {
  906.             unselect_unit_on_map(map, unit);
  907.             select_unit_on_map(map, nextocc);
  908.             /* Overkill, but draw_row alone not as desirable? */
  909.             update_cell_display(dside, unit->x, unit->y, TRUE);
  910.         }
  911.     }
  912.     return TRUE;
  913. }
  914.  
  915. void
  916. do_occupant()
  917. {
  918.     apply_to_all_selected(do_one_occupant, TRUE);
  919. }
  920.  
  921. void
  922. do_other()
  923. {
  924.     /* Don't allow recursion with this command. */
  925.     if (!doingother) {
  926.         doingother = TRUE;
  927.         enable_command();
  928.         doingother = FALSE;
  929.     } else {
  930.         beep();
  931.     }
  932. }
  933.  
  934. /* Dialog for the input of a textual command. */
  935.  
  936. WindowPtr commandwin;
  937.  
  938. ControlHandle dobutton;
  939.  
  940. TEHandle command_text = nil;
  941.  
  942. Rect commandtextrect;
  943.  
  944. void create_command_dialog(void);
  945.  
  946. static void get_command_and_do(void);
  947.  
  948. void
  949. enable_command()
  950. {
  951.     if (commandwin == nil) {
  952.         create_command_dialog();
  953.     }
  954.     if (commandwin != nil) {
  955.         ShowWindow(commandwin);
  956.         SelectWindow(commandwin);
  957.     }
  958. }
  959.  
  960. void
  961. create_command_dialog()
  962. {
  963.     Rect tmprect;
  964.  
  965.     if (hasColorQD) {
  966.         commandwin = GetNewCWindow(wCommand, NULL, (WindowPtr) -1L);
  967.     } else {
  968.         commandwin = GetNewWindow(wCommand, NULL, (WindowPtr) -1L);
  969.     }
  970.     dobutton = GetNewControl(cCommandDoButton, commandwin);
  971.     SetPort(commandwin);
  972.     tmprect = commandwin->portRect;
  973.     commandtextrect = tmprect;
  974.     commandtextrect.bottom -= 30;
  975.     InsetRect(&commandtextrect, 5, 5);
  976.     /* Create and clear the TextEdit record. */
  977.     command_text = TENew(&commandtextrect, &commandtextrect);
  978.     TESetSelect(0, 32767, command_text);
  979.     TEDelete(command_text);
  980.     ShowWindow(commandwin);
  981. }
  982.  
  983. void
  984. draw_command()
  985. {
  986.     Rect tmprect;
  987.  
  988.     TEUpdate(&(commandwin->portRect), command_text);
  989.     tmprect = commandtextrect;
  990.     InsetRect(&tmprect, -1, -1);
  991.     FrameRect(&tmprect);
  992. }
  993.  
  994. void
  995. activate_command(int activate)
  996. {
  997.     if (activate)
  998.       TEActivate(command_text);
  999.     else
  1000.       TEDeactivate(command_text);
  1001. }
  1002.  
  1003. int
  1004. do_key_down_command(key)
  1005. int key;
  1006. {
  1007.     if (key == 13 || key == 3) {
  1008.         get_command_and_do();
  1009.     } else {
  1010.         TEKey(key, command_text);
  1011.     }
  1012.     return TRUE;
  1013. }
  1014.  
  1015. void
  1016. do_mouse_down_command(Point mouse, int mods)
  1017. {
  1018.     short part;
  1019.     ControlHandle control;
  1020.  
  1021.     part = FindControl(mouse, commandwin, &control);
  1022.     if (control == dobutton) {
  1023.         get_command_and_do();
  1024.     } else if (PtInRect(mouse, &commandtextrect)) {
  1025.         TEClick(mouse, mods, command_text);
  1026.     }
  1027. }
  1028.  
  1029. static void
  1030. get_command_and_do()
  1031. {
  1032.     int len;
  1033.     char buffer[BUFSIZE];
  1034.     CharsHandle text;
  1035.  
  1036.     text = TEGetText(command_text);
  1037.     len = min((*command_text)->teLength, BUFSIZE);
  1038.     strncpy(buffer, *text, len);
  1039.     buffer[len] = '\0';
  1040.     if (!empty_string(buffer)) {
  1041.         execute_named_command(buffer);
  1042.     } else {
  1043.         notify(dside, "No command.");
  1044.         beep();
  1045.     }
  1046. }
  1047.  
  1048. void
  1049. do_print_view()
  1050. {
  1051.     dump_ps_view(dside, NULL, "View PS");
  1052. }
  1053.  
  1054. static void unit_do_produce_2(Unit *unit);
  1055.  
  1056. void
  1057. do_produce()
  1058. {
  1059.     int i;
  1060.     Map *map;  List *list;  UnitCloseup *closeup;
  1061.     Unit *unit;
  1062.  
  1063.     /* Try different alternatives to find a unit. */
  1064.     map = map_from_window(FrontWindow());
  1065.     if (map != NULL) {
  1066.         for (i = 0; i < map->numselections; ++i) {
  1067.             unit = map->selections[i];
  1068.             if (unit != NULL && can_produce(unit)) {
  1069.                 unit_do_produce_2(unit);
  1070.                 return;
  1071.             }
  1072.         }
  1073.         return;
  1074.     }
  1075.     list = list_from_window(FrontWindow());
  1076.     if (list != NULL) {
  1077.         unit = selected_unit_in_list(list);
  1078.         if (unit != NULL && can_produce(unit)) {
  1079.             unit_do_produce_2(unit);
  1080.             return;
  1081.         }
  1082.         return;
  1083.     }
  1084.     closeup = unit_closeup_from_window(FrontWindow());
  1085.     if (closeup != NULL) {
  1086.         unit = closeup->unit;
  1087.         if (unit != NULL && can_produce(unit)) {
  1088.             unit_do_produce_2(unit);
  1089.             return;
  1090.         }
  1091.         return;
  1092.     }
  1093.     /* No way to figure out the unit to be producing with, so complain. */
  1094.     beep();
  1095. }
  1096.  
  1097. static void
  1098. unit_do_produce_2(Unit *unit)
  1099. {
  1100.     int m, n;
  1101.  
  1102.     n = 9999;
  1103.     if (prefixarg > 0)
  1104.       n = prefixarg;
  1105.     for_all_material_types(m) {
  1106.         if (um_acp_to_produce(unit->type, m) > 0) {
  1107.             push_produce_task(unit, m, n);
  1108.             return;
  1109.         }
  1110.     }
  1111. }
  1112.  
  1113. void
  1114. do_quit()
  1115. {
  1116.     quit_the_game();
  1117. }
  1118.  
  1119. static int allsumx, allsumy, unitcount;
  1120.  
  1121. static int
  1122. add_unit_position(Unit *unit)
  1123. {
  1124.     allsumx += unit->x;  allsumy += unit->y;
  1125.     ++unitcount;
  1126.     return TRUE;
  1127. }
  1128.  
  1129. void
  1130. do_recenter()
  1131. {
  1132.     int avgx, avgy;
  1133.     Map *map;
  1134.  
  1135.     map = map_from_window(FrontWindow());
  1136.     if (map != NULL) {
  1137.         allsumx = allsumy = 0;
  1138.         unitcount = 0;
  1139.         apply_to_all_selected(add_unit_position, FALSE);
  1140.         if (unitcount == 0) {
  1141.             beep();
  1142.             return;
  1143.         }
  1144.         avgx = allsumx / unitcount;  avgy = allsumy / unitcount;
  1145.         set_focus(map, avgx, avgy);
  1146.     }
  1147. }
  1148.  
  1149. void
  1150. set_focus(Map *map, int x, int y)
  1151. {
  1152.     if (!inside_area(x, y))
  1153.       return;
  1154.     set_view_focus(map->vp, x, y);
  1155.     m_center_on_focus(map);
  1156.     set_map_scrollbars(map);
  1157.     force_map_update(map);
  1158. }
  1159.  
  1160. /* Recalculate and redraw everything. */
  1161.  
  1162. void
  1163. do_refresh()
  1164. {
  1165.     Map *map;
  1166.     List *list;
  1167.     UnitCloseup *closeup;
  1168.  
  1169.     reset_coverage();
  1170.     reset_all_views();
  1171.     compute_all_feature_centroids();
  1172.     /* Force updates to all open windows. */
  1173.     force_update(gamewin);
  1174.     force_update(noticewin);
  1175.     force_update(historywin);
  1176.     force_update(constructionwin);
  1177.     force_update(helpwin);
  1178.     for_all_maps(map) {
  1179.         force_update(map->window);
  1180.     }
  1181.     for_all_lists(list) {
  1182.         force_update(list->window);
  1183.     }
  1184.     for_all_unit_closeups(closeup) {
  1185.         force_update(closeup->window);
  1186.     }
  1187. }
  1188.  
  1189. void
  1190. do_remove_terrain()
  1191. {
  1192.     int x, y, dir;
  1193.     Map *map;
  1194.     
  1195.     if (get_a_position(&map, &x, &y, &dir)) {
  1196.         tmpcmdx = x;  tmpcmdy = y;  tmpcmddir = dir;
  1197.         apply_to_all_selected(do_one_remove_terrain, TRUE);
  1198.         return;
  1199.     }
  1200.     beep();
  1201. }
  1202.  
  1203. static int
  1204. do_one_remove_terrain(Unit *unit)
  1205. {
  1206.     int u, t, x, y, dir;
  1207.  
  1208.     u = unit->type;
  1209.     for_all_terrain_types(t) {
  1210.         if (ut_acp_to_remove_terrain(u, t) > 0
  1211.             && unit->act
  1212.             && unit->act->acp >= ut_acp_to_remove_terrain(u, t)) {
  1213.             if (distance(tmpcmdx, tmpcmdy, unit->x, unit->y) <= ut_alter_range(u, t)) {
  1214.                 x = tmpcmdx;  y = tmpcmdy;
  1215.                 dir = tmpcmddir;
  1216.             } else {
  1217.                 x = unit->x;  y = unit->y;
  1218.                 dir = approx_dir(tmpcmdx - unit->x, tmpcmdy - unit->y);
  1219.             }
  1220.             if (valid(check_remove_terrain_action(unit, unit, x, y, dir, t))) {
  1221.                 if (prep_remove_terrain_action(unit, unit, x, y, dir, t))
  1222.                   return TRUE;
  1223.             }
  1224.         }
  1225.     }
  1226.     return FALSE;
  1227. }
  1228.  
  1229. static int
  1230. do_one_reserve(Unit *unit)
  1231. {
  1232.     set_unit_reserve(dside, unit, tmpcmdarg, tmprecurse);
  1233.     return TRUE;
  1234. }
  1235.  
  1236. void
  1237. do_reserve_command(int value, int radius, int recurse)
  1238. {
  1239.     tmpcmdarg = value;
  1240.     tmprecurse = recurse;
  1241.     apply_to_all_selected(do_one_reserve, TRUE);    
  1242. }
  1243.  
  1244. void
  1245. do_reserve()
  1246. {
  1247.     do_reserve_command(TRUE, prefixarg, FALSE);
  1248. }
  1249.  
  1250. static int
  1251. do_one_return(Unit *unit)
  1252. {
  1253.     if (1 /* has a place to return to */) {
  1254.         set_resupply_task(unit, NONMTYPE);
  1255.         return TRUE;
  1256.     }
  1257.     return FALSE;
  1258. }
  1259.  
  1260. void
  1261. do_return()
  1262. {
  1263.     apply_to_all_selected(do_one_return, TRUE);    
  1264. }
  1265.  
  1266. void
  1267. do_resign()
  1268. {
  1269.     if (endofgame) {
  1270.         notify(dside, "Game is already over.");
  1271.         beep();
  1272.     } else if (!dside->ingame) {
  1273.         notify(dside, "You are already out of the game.");
  1274.         beep();
  1275.     } else if (CautionAlert(aConfirmResign, nil) == aiConfirmResignResign) {
  1276.         resign_game(dside, NULL);
  1277.     }
  1278. }
  1279.  
  1280. void
  1281. do_save()
  1282. {
  1283.     save_the_game(FALSE, FALSE);
  1284. }
  1285.  
  1286. void
  1287. do_set_formation()
  1288. {
  1289.     int i, numcould = 0, numnot = 0;
  1290.     Map *map;
  1291.     Unit *follower, *leader;
  1292.     
  1293.     if (get_a_unit(&map, &leader)) {
  1294.         if (leader != NULL) {
  1295.             for (i = 0; i < map->numselections; ++i) {
  1296.                 if ((follower = map->selections[i]) != NULL && valid_selection(follower)) {
  1297.                     if (leader != follower
  1298.                         && leader->side == follower->side
  1299.                         ) {
  1300.                         set_formation(follower, leader, follower->x - leader->x, follower->y - leader->y, 1, 1);
  1301.                         ++numcould;
  1302.                     } else {
  1303.                         ++numnot;
  1304.                     }
  1305.                 }
  1306.             }
  1307.         } else {
  1308.             /* Can't make a formation without a leader. */
  1309.             cmd_error(dside, "no leader found");
  1310.         }
  1311.     }
  1312.     /* If nobody could do the command, beep once. */
  1313.     if (numcould == 0 && numnot > 0) {
  1314.         beep();
  1315.     }
  1316. }
  1317.  
  1318. void
  1319. do_set_rate()
  1320. {
  1321.     int slow, fast;
  1322.     char *reststr;
  1323.  
  1324.     if (cmdargstr) {
  1325.         slow = strtol(cmdargstr, &reststr, 10);
  1326.         fast = strtol(reststr, &reststr, 10);
  1327.         set_play_rate(slow, fast);
  1328.     }
  1329. }
  1330.  
  1331. static int
  1332. do_one_asleep(Unit *unit)
  1333. {
  1334.     set_unit_asleep(dside, unit, tmpcmdarg, tmprecurse);
  1335.     return TRUE;
  1336. }
  1337.  
  1338. void
  1339. do_sleep_command(int value, int radius, int recurse)
  1340. {
  1341.     tmpcmdarg = value;
  1342.     tmprecurse = recurse;
  1343.     apply_to_all_selected(do_one_asleep, TRUE);    
  1344. }
  1345.  
  1346. void
  1347. do_sleep()
  1348. {
  1349.     do_sleep_command(TRUE, prefixarg, FALSE);
  1350. }
  1351.  
  1352. void
  1353. do_standing_orders()
  1354. {
  1355.     int rslt;
  1356.  
  1357.     if (cmdargstr) {
  1358.         rslt = parse_standing_order(dside, cmdargstr);
  1359.         if (rslt < 0)
  1360.           beep();
  1361.     } else
  1362.       beep();
  1363. }
  1364.  
  1365. void
  1366. do_surrender_to()
  1367. {
  1368.     beep();
  1369. }
  1370.  
  1371. void 
  1372. do_survey()
  1373. {
  1374.     Map *map;
  1375.  
  1376.     map = map_from_window(FrontWindow());
  1377.     if (map != NULL) {
  1378.         toggle_survey(map);
  1379.     }
  1380. }
  1381.  
  1382. void
  1383. do_take()
  1384. {
  1385.     /* (should use argument) */
  1386.     apply_to_all_selected(do_one_take, TRUE);
  1387. }
  1388.  
  1389. void
  1390. do_take_unit()
  1391. {
  1392.     beep();
  1393. }
  1394.  
  1395. void
  1396. do_trust()
  1397. {
  1398.     Side *side2;
  1399.  
  1400.     if (cmdargstr) {
  1401.         side2 = parse_side_spec(cmdargstr);
  1402.         if (side2 != NULL && side2 != dside) {
  1403.             set_trust(dside, side2, 1);
  1404.             return;
  1405.         } 
  1406.     }
  1407.     beep();
  1408. }
  1409.  
  1410. void
  1411. do_version()
  1412. {
  1413.     do_about_box();
  1414. }
  1415.  
  1416. void
  1417. do_wake()
  1418. {
  1419.     do_sleep_command(FALSE, prefixarg, FALSE);
  1420.     do_reserve_command(FALSE, prefixarg, FALSE);
  1421. }
  1422.  
  1423. void
  1424. do_wake_all()
  1425. {
  1426.     do_sleep_command(FALSE, prefixarg, TRUE);
  1427.     do_reserve_command(FALSE, prefixarg, TRUE);
  1428. }
  1429.  
  1430. void
  1431. do_warranty()
  1432. {
  1433.     help_dialog(warranty_help_node);
  1434. }
  1435.  
  1436. #ifdef DESIGNERS
  1437.  
  1438. /* Toggle the designer mode. */
  1439.  
  1440. void
  1441. do_design()
  1442. {
  1443.     if (!dside->designer) {
  1444.         enable_designing(FALSE);
  1445.     } else {
  1446.         disable_designing();
  1447.     }
  1448. }
  1449.  
  1450. void
  1451. do_gdl()
  1452. {
  1453.     if (cmdargstr)
  1454.       interp_form(NULL, read_form_from_string(cmdargstr, NULL, NULL));
  1455.     else
  1456.       beep();
  1457.     end_printing_forms();
  1458. }
  1459.  
  1460. #endif
  1461.  
  1462. #ifdef DEBUGGING
  1463.  
  1464. void
  1465. do_debug()
  1466. {
  1467.     toggle_debugging(&Debug);
  1468.     draw_game();
  1469. }
  1470.  
  1471. void
  1472. do_debugg()
  1473. {
  1474.     toggle_debugging(&DebugG);
  1475.     draw_game();
  1476. }
  1477.  
  1478. void
  1479. do_debugm()
  1480. {
  1481.     toggle_debugging(&DebugM);
  1482.     draw_game();
  1483. }
  1484.  
  1485. void
  1486. do_profile()
  1487. {
  1488.     toggle_profiling();
  1489. }
  1490.  
  1491. void
  1492. do_trace()
  1493. {
  1494.     toggle_profiling();
  1495. #ifdef PROFILING
  1496.     _trace = 1;
  1497. #endif
  1498. }
  1499.  
  1500. #endif
  1501.  
  1502. /* End of alphabetized commands. */
  1503.  
  1504. /* Mac-specific command functions. */
  1505.  
  1506. void
  1507. do_mac_escape()
  1508. {
  1509.     map_modal = NO_MODAL;
  1510. }
  1511.  
  1512. void
  1513. do_mac_set_map_angle()
  1514. {
  1515.     int angle;
  1516.     Map *map;
  1517.  
  1518.     map = map_from_window(FrontWindow());
  1519.     if (map != NULL) {
  1520.         angle = map->vp->angle;
  1521.         if (angle == 90)
  1522.           angle = 30;
  1523.         else if (angle == 30)
  1524.           angle = 15;
  1525.         else
  1526.           angle = 90;
  1527.         map->vp->vertscale = (prefixarg < 1 ? 1 : prefixarg);
  1528.         set_view_angle(map->vp, angle);
  1529.         force_map_update(map);
  1530.     }
  1531. }
  1532.  
  1533. void
  1534. do_mac_zoom_in()
  1535. {
  1536.     Map *map;
  1537.  
  1538.     map = map_from_window(FrontWindow());
  1539.     if (map != NULL) {
  1540.         magnify_map(map, 1);
  1541.     } else {
  1542.         beep();
  1543.     }
  1544. }
  1545.  
  1546.  
  1547. void
  1548. do_mac_zoom_out()
  1549. {
  1550.     Map *map;
  1551.  
  1552.     map = map_from_window(FrontWindow());
  1553.     if (map != NULL) {
  1554.         magnify_map(map, -1);
  1555.     } else {
  1556.         beep();
  1557.     }
  1558. }
  1559.  
  1560. #ifdef DEBUGGING
  1561.  
  1562. void
  1563. toggle_profiling()
  1564. {
  1565. #ifdef PROFILING
  1566.     extern int _profile;
  1567. #endif
  1568.  
  1569.     Profile = !Profile;
  1570.  
  1571. #ifdef PROFILING
  1572. #ifdef THINK_C
  1573.     if (Profile && !_profile) {
  1574.         InitProfile(1000, 100);
  1575.         freopen("Xconq.ProfileOut", "w", stdout);
  1576.     }
  1577.     if (!Profile && _profile) {
  1578.         DumpProfile();
  1579.         fflush(stdout);
  1580.     }
  1581. #endif
  1582. #endif
  1583. }
  1584.  
  1585. #endif /* DEBUGGING */
  1586.  
  1587. /* Generic command error feedback. */
  1588.  
  1589. static void
  1590. cmd_error(Side *side, char *fmt, ...)
  1591. {
  1592.     va_list ap;
  1593.  
  1594.     va_start(ap, fmt);
  1595.     vnotify(side, fmt, ap);
  1596.     va_end(ap);
  1597.     /* (should) Only beep once, even if a command generates multiple error messages. */
  1598.     beep();
  1599. }
  1600.