/* Menus and commands for the Mac interface to Xconq.
   Copyright (C) 1992-1998, 2000 Stanley T. Shebs.

Xconq is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.  See the file COPYING.  */

#include "conq.h"
extern short *aux_terrain_type_index;
#include "print.h"
#include "macconq.h"

#ifdef THINK_C
#include <profile.h>
#endif

#ifdef DESIGNERS
#define side_may_select(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
#define valid_selection(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
#define menus_tweakable() ((!beforestart && !endofgame) || (gameinited && dside->designer))
#else /* n DESIGNERS */
#define side_may_select(unit) (in_play(unit) && ((unit)->side == dside))
#define valid_selection(unit) (in_play(unit) && ((unit)->side == dside))
#define menus_tweakable() ((!beforestart && !endofgame) || (gameinited))
#endif /* DESIGNERS */

#define MAXWINDOWS 100

static void build_ai_type_menu(void);
static void maybe_init_print(void);
static void resign_the_game(int forced);
static void te_cut(TEHandle hdl);
static void te_copy(TEHandle hdl);
static void te_paste(TEHandle hdl);

static void do_page_setup_mi(void);
static void do_print_mi(void);
static void do_select_all_mi(void);
static void do_find_previous_mi(void);
static void do_find_next_mi(void);
static void do_find_location_mi(void);
static void do_find_unit_by_name_mi(void);
static int find_location_dialog(int *xp, int *yp);
static int worldmap_dialog(void);
static int find_unit_dialog(Unit **unitp);
static int find_something(Side *side, char *str, int findunit, int *xp, int *yp, Unit **unitp);
static void do_find_selected_mi(void);
static void do_closeup_mi(void);	
static void do_overrun_mi(void);
static void moveonclick_mi(void);
static void do_plan_type_mi(void);
static int do_one_plan_type(Unit *unit);
static void do_take_mi(void);
static void autoselect_mi(void);
static void do_detonate_mi(void);
static void do_give_unit_mi(int mi);

static void adjust_menu_item(MenuHandle menu, int item, int value);
static void enable_commands_for_unit(MenuHandle menu, MenuHandle menu2, Unit *unit);

static void set_offscreen_buffers(Map *map);
static void set_meridians(Map *map);
static void seed_side_rename_string(DialogPtr win, short ditem, char *str);
static char *get_side_rename_string(DialogPtr win, short ditem);
static void side_rename_dialog(Side *side);

static void toggle_map_topline(Map *map);
static void toggle_map_topunit(Map *map);
static void toggle_map_scrollbars(Map *map);
static void toggle_map_cpanel(Map *map);
static void toggle_map_other_maps(Map *map);
static void toggle_map_lighting(Map *map);
static void toggle_map_coverage(Map *map);
static void toggle_map_names(Map *map);
static void toggle_map_elevations(Map *map);
static void toggle_map_materials(Map *map, int m);
static void toggle_map_aux_terrain(Map *map, int t);
static void toggle_map_temperature(Map *map);
static void toggle_map_winds(Map *map);
static void toggle_map_clouds(Map *map);
static void toggle_map_storms(Map *map);
static void toggle_map_draw_emblems(Map *map);
static void toggle_blinking_curunit(Map *map);
static void toggle_selectionmasks(Map *map);
static void toggle_iconmasks(Map *map);
static void toggle_boxmasks(Map *map);
static void toggle_textmasks(Map *map);
static void toggle_featureborders(Map *map);
static void toggle_featurenames(Map *map);
static void toggle_shorelines(Map *map);
static void toggle_simple_borders(Map *map);
static void toggle_optimize_fonts(Map *map);
static void toggle_erase_names(Map *map);
static void toggle_draw_meridians(Map *map);
static void toggle_solid_color_terrain(Map *map);

Side *tmpcmdside;

int numwindows = 0;

int tmp_plan_type;

int forcedtoresign;

int Profile = FALSE;

int feature_menu_size;

short *feature_menu_fids;

char *cursavename = NULL;

MenuHandle mapviewmenu = nil;
MenuHandle listviewmenu = nil;
MenuHandle closeupviewmenu = nil;
MenuHandle colorsmenu = nil;
MenuHandle utypemenu = nil;
MenuHandle ttypemenu = nil;
MenuHandle mtypemenu = nil;
MenuHandle sidemenu = nil;
MenuHandle aitypemenu = nil;
MenuHandle featuremenu = nil;
MenuHandle optterrmenu = nil;

/* This is the array of windows that the Windows menu references. */
WindowPtr *winmenuwins;

WindowPtr worldmapwin = nil;

Map *worldmap = NULL;

void
query_position_modally(int mode)
{
	if (map_modal == NO_MODAL) {

		/* Since we now allow selection of enemy units it is important to unselect 
		them before any modal commands are executed for the list of selected units. 
		The totalselections and unselected stuff is needed because both selections[i] 
		and numselections change within the loop. */
		int	totalselections;
		int	i, unselected = 0;
		Unit	*unit;
		
		if (frontmap) {
			totalselections = frontmap->numselections;
			for (i = 0; i < totalselections; ++i) {
				unit = frontmap->selections[i - unselected];
				if (!side_controls_unit(dside, unit)) {
					unselect_unit_on_map(frontmap, unit);
					update_cell(frontmap, unit->x, unit->y);
					unselected++;
				}
			}
		}
		/* Note: attempts to execute menu commands for non-controlled units
		are also intercepted in apply_to_all_selected_units. Still, unselecting
		non-controlled units here is a good idea since it reveals exactly which 
		units on the map will be affected by the command. */

		map_modal = mode;
	} else {
		beep();
	}
}

void
set_position_modally()
{
	modal_map = frontmap;
	GetMouse(&modal_point);
	position_set_modally = TRUE;
}

/* Set up all the menus, at least in their basic form. */

void
init_menus()
{
	int i;
	Handle menubar;
	MenuHandle menu;

	menubar = GetNewMBar(mbMain);
	SetMenuBar(menubar);
	/* Add the DAs etc as usual. */
	menu = GetMHandle(mApple);
	if (menu != nil)
	  AddResMenu(menu, 'DRVR');
	/* Get the different versions of the view menu. */
	mapviewmenu = GetMenu(mViewMap);
	listviewmenu = GetMenu(mViewList);
	closeupviewmenu = GetMenu(mViewCloseup);
	/* Init submenus and popups. */
	colorsmenu = GetMenu(mColors);
	if (colorsmenu != nil)
	  InsertMenu(colorsmenu, -1);
	menu = GetMenu(mMagnifications);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mViewWeather);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mViewAngles);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mPlanTypes);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mViewText);
	if (menu != nil)
	  InsertMenu(menu, -1);

	menu = GetMenu(mViewGrids);
	if (menu != nil)
	  InsertMenu(menu, -1);

	menu = GetMenu(mViewColors);
	if (menu != nil)
	  InsertMenu(menu, -1);

	menu = GetMenu(mViewBorders);
	if (menu != nil)
	  InsertMenu(menu, -1);

	sidemenu = GetMenu(mSides);
	if (sidemenu != nil)
	  InsertMenu(sidemenu, -1);
	utypemenu = GetMenu(mUnitTypes);
	if (utypemenu != nil)
	  InsertMenu(utypemenu, -1);
	mtypemenu = GetMenu(mMaterialTypes);
	if (mtypemenu != nil)
	  InsertMenu(mtypemenu, -1);
	ttypemenu = GetMenu(mTerrainTypes);
	if (ttypemenu != nil)
	  InsertMenu(ttypemenu, -1);
	aitypemenu = GetMenu(mAITypes);
	if (aitypemenu != nil)
	  InsertMenu(aitypemenu, -1);
	featuremenu = GetMenu(mFeatures);
	if (featuremenu != nil)
	  InsertMenu(featuremenu, -1);
	optterrmenu = GetMenu(mOptTerrainTypes);
	if (optterrmenu != nil)
	  InsertMenu(optterrmenu, -1);
	/* Init the support for the Windows menu. */
	winmenuwins = (WindowPtr *) xmalloc(MAXWINDOWS * sizeof(WindowPtr));
	for (i = 0; i < MAXWINDOWS; ++i)
	  winmenuwins[i] = nil;
	numwindows = 0;
	/* Done fiddling with menus, draw them. */
	DrawMenuBar();
}

/* Add a menu item that can be used to go to the given window.  Set the window title
   here too, ensures that the two match. */

void
add_window_menu_item(char *name, WindowPtr win)
{
	MenuHandle menu;
	Str255 tmpstr;

	if (numwindows < MAXWINDOWS) {
		c2p(name, tmpstr);
		SetWTitle(win, tmpstr);
		winmenuwins[numwindows++] = win;
		menu = GetMHandle(mWindows);
		if (menu != nil)
	  	    AppendMenu(menu, tmpstr);
	}
}

/* Remove the menu item that can be used to select a given window. */

void
remove_window_menu_item(WindowPtr win)
{
	int i, found = FALSE, next = 0;
	Str255 tmpstr;
	MenuHandle menu;

	/* Search for the window and remove it from the array of windows
	   that have menu items. */
	for (i = 0; i < numwindows; ++i) {
		if (!found && winmenuwins[i] == win) {
			found = TRUE;
		}
		if (found && i < numwindows - 1) {
			/* Shift the other windows down. */
			winmenuwins[i] = winmenuwins[i + 1];
		}
	}
	/* This routine gets called for all windows, so get out of here
	   if this window is not one of those in the menu. */
	if (!found)
	  return;
	--numwindows;
	/* Trash the existing window menu. */
	menu = GetMHandle(mWindows);
	if (menu != nil) {
		DeleteMenu(mWindows);
		ReleaseResource((Handle) menu);
	}
	/* Build a new version starting with the resource. */
	menu = GetMenu(mWindows);
	if (menu != nil) {
		for (i = 0; i < numwindows; ++i) {
			GetWTitle(winmenuwins[i], tmpstr);
			AppendMenu(menu, tmpstr);
		}
		/* Glue a view menu on after the windows menu. */
		if (GetMHandle(mViewMap) != nil)
		  next = mViewMap;
		if (GetMHandle(mViewList) != nil)
		  next = mViewList;
		InsertMenu(menu, next);
	}
	DrawMenuBar();
}

/* Fill up the side menu. */

void
build_side_menu()
{
	char *title;
	Side *side2;
	Str255 tmpstr;

	if (sidemenu != nil && CountMItems(sidemenu) < 1) {
		for_all_sides(side2) {
			title = shortest_side_title(side2, spbuf);
			sanitize_for_menu(title, tmpstr);
			AppendMenu(sidemenu, tmpstr);
			EnableItem(sidemenu, side_number(side2));
		}
	}
}

void
update_side_menu(Side *side2)
{
	char *title;
	Str255 tmpstr;

	title = shortest_side_title(side2, spbuf);
	sanitize_for_menu(title, tmpstr);
	SetMenuItemText(sidemenu, side_number(side2), tmpstr);
}

void
build_unit_type_menu()
{
	int u;
	Str255 tmpstr;

	if (utypemenu != nil && CountMItems(utypemenu) < 1) {
		for_all_unit_types(u) {
			sanitize_for_menu(u_type_name(u), tmpstr);
			AppendMenu(utypemenu, tmpstr);
			EnableItem(utypemenu, u + 1);
		}
	}
}

void
build_material_type_menu()
{
	int m;
	Str255 tmpstr;

	if (mtypemenu != nil && CountMItems(mtypemenu) < 1 && nummtypes > 0) {
		for_all_material_types(m) {
			sanitize_for_menu(m_type_name(m), tmpstr);
			AppendMenu(mtypemenu, tmpstr);
			EnableItem(mtypemenu, m + 1);
		}
	}
}

void
build_terrain_type_menu()
{
	int t;
	Str255 tmpstr;

	if (ttypemenu != nil && CountMItems(ttypemenu) < 1) {
		for_all_terrain_types(t) {
			sanitize_for_menu(t_type_name(t), tmpstr);
			AppendMenu(ttypemenu, tmpstr);
			EnableItem(ttypemenu, t);
		}
	}
}

void
build_ai_type_menu()
{
	char *aitypename;

	/* Permit AIs to be dynamically added to the menu. */
	if (aitypemenu != nil && CountMItems(aitypemenu) < 1) {

		Str255	pname;
		int		i;

		AppendMenu(aitypemenu, "\pNone");
		EnableItem(aitypemenu, 1);
		aitypename = next_ai_type_name(NULL);
		i = 1;
		while (aitypename != NULL) {
			c2p(aitypename, pname);
			AppendMenu(aitypemenu, pname);
			EnableItem(aitypemenu, i + 1);
			aitypename = next_ai_type_name(aitypename);
			++i;
		}
	}
}

void
build_feature_menu()
{
	int i, newsize;
	char *name;
	Str255 tmpstr;
	Feature *feature;
	MenuHandle oldmenu, newmenu = nil;

	if (featuremenu != nil) {
		if (CountMItems(featuremenu) >= 1) {
			/* Trash the existing feature menu. */
			oldmenu = GetMHandle(mFeatures);
			if (oldmenu != nil) {
				DeleteMenu(mFeatures);
				ReleaseResource((Handle) oldmenu);
				/* Build a new version starting with the resource. */
				if ((newmenu = GetMenu(mFeatures)) != nil) {
					featuremenu = newmenu;
				}
			}
		}
		/* Allocate the lookup array that maps menu items to actual feature ids. */
		newsize = 1;
		for_all_features(feature) {
			++newsize;
		}
		if (newsize != feature_menu_size) {
			if (feature_menu_size > 0)
			  free(feature_menu_fids);
			feature_menu_size = newsize;
			feature_menu_fids =
			  (short *) xmalloc(feature_menu_size * sizeof(short));
		}
		i = 0;
		/* The first item is used to clear features. */
		AppendMenu(featuremenu, "\pNo Feature");
		EnableItem(featuremenu, i + 1);
		feature_menu_fids[i++] = 0;
		for_all_features(feature) {
			name = feature_desc(feature, spbuf);
			sanitize_for_menu(name, tmpstr);
			AppendMenu(featuremenu, tmpstr);
			EnableItem(featuremenu, i + 1);
			feature_menu_fids[i++] = feature->id;
		}
		if (newmenu != nil) {
			InsertMenu(featuremenu, -1);
		}
	}
}

void
build_optional_terrain_type_menu()
{
	int t;
	Str255 tmpstr;

	if (optterrmenu != nil && CountMItems(optterrmenu) < 1) {
		for_all_terrain_types(t) {
			if (!t_is_cell(t)) {
				sanitize_for_menu(t_type_name(t), tmpstr);
				AppendMenu(optterrmenu, tmpstr);
				EnableItem(optterrmenu, t);
			}
		}
		if (CountMItems(optterrmenu) < 1)
		  optterrmenu = nil;
	}
}

/* This removes chars that are specially recognized by the Menu Manager.
   Has to be done so that strange game-defined names don't scramble the
   menus; innocuous because this affects only the appearance in the menu. */

extern void
sanitize_for_menu(char *str, Str255 outstr)
{
	int i = 0;

	/* Replace special chars with blanks. */
	for (i = 0; str[i] != '\0' && i < 255; ++i) {
		switch (str[i]) {
			case ';':
			case '!':
			case '<':
			case '/':
			case '(':
			/* I don't think closing parens are special, but since the
			   (presumed) matching open paren is gone, might as well get
			   rid of the close also. */
			case ')':
				outstr[i + 1] = ' ';
				break;
			default:
				outstr[i + 1] = str[i];
				break;
		}
	}
	outstr[i + 1] = '\0';
	/* Replace a leading hyphen with an underscore. */
	if (outstr[1] == '-')
	  outstr[1] = '_';
	outstr[0] = i;
}

/* Decipher and do a menu command. */

/* Note: do_menu_command and most do_something_mi now use frontmap instead 
of FrontWindow (or topWindow) and will therefore work also when the frontmap
is in a background window. However, the menu commands are not accesible in that
case since adjust_menus still works with the topWindow. */

void
do_menu_command(long which)
{
	short menuid, menuitem, daRefNum;
	unsigned char keyMap[16];
	int optionKey;
	Str255 daname;
	WindowPtr win;
	Map *map;

	menuid = HiWord(which);
	menuitem = LoWord(which);
	DGprintf("menu %d, item %d\n", menuid, menuitem);

	/* Access world map if control key is down. */	
	GetKeys((GETKEYS_ARG_TYPE) keyMap);
	optionKey = keyMap[0x3A >> 3] >> (0x3A & 7) & 1;
	if (optionKey && worldmap)
		map = worldmap;
	else	map = frontmap;	

	switch (menuid) {
		case mApple:
			switch (menuitem) {
				case miAppleAbout:
					do_about_box();
					break;
				case miAppleHelp:
					show_help_window(NULL);
					break;
				case miAppleInstructions:
					show_instructions_window();
					break;
				default:
					GetItem(GetMHandle(mApple), menuitem, daname);
					daRefNum = OpenDeskAcc(daname);
			}
			break;
		case mFile:
			switch (menuitem) {
				case miFileNew:
					/* (should reset state of everything first) */
					new_game_dialog();
					break;
				case miFileOpen:
					/* (should reset state of everything first) */
					open_game_dialog();
					break;
				case miFileConnect:
					connect_game_dialog();
					break;
				case miFileClose:
					close_window(topWindow);
					break;
				case miFileSave:
					save_the_game(FALSE, FALSE);
					break;
				case miFileSaveAs:	
					save_the_game(TRUE, FALSE);
					break;
				case miFilePreferences:
					set_preferences();
					break;
				case miFilePageSetup:
					do_page_setup_mi();
					break;
				case miFilePrintWindow:
					do_print_mi();
					break;
				case miFileResign:
					do_resign(dside);
					break;
				case miFileQuit:
					quit_the_game();
					break;
			}
			break;
		case mEdit:
			if (SystemEdit(menuitem - 1))
			  break;
			switch (menuitem)  {
				case miEditCut:
					if (topWindow == commandwin) {
						te_cut(command_text);
					} else if(topWindow == constructionwin) {
						te_cut(run_length_text);
					}
					break;
				case miEditCopy:
					if (topWindow == commandwin) {
						te_copy(command_text);
					} else if(topWindow == constructionwin) {
						te_copy(run_length_text);
					}
					break;
				case miEditPaste:
					if (topWindow == commandwin) {
						te_paste(command_text);
					} else if (topWindow == constructionwin) {
						te_paste(run_length_text);
					}
					break;
				case miEditClear:
					if (topWindow == commandwin) {
						TEDelete(command_text);						
					} else if (topWindow == constructionwin) {
						TEDelete(run_length_text);						
					}
					break;
				case miEditSelectAll:
					do_select_all_mi();
					break;
#ifdef DESIGNERS
				case miEditDesign:
					do_design(dside);
					break;
#endif
			}
			break;
		case mFind:
			switch (menuitem) {
				case miFindPrevious:
					do_find_previous_mi();
					break;
				case miFindNext:
					do_find_next_mi();
					break;
				case miFindNextOccupant:
					do_occupant(dside);
					break;
				case miFindLocation:
					do_find_location_mi();
					break;
				case miFindUnitByName:
					do_find_unit_by_name_mi();
					break;
				case miFindDistance:
					do_distance(dside);
					break;
				case miFindSelected:
					do_find_selected_mi();
					break;
			}
			break;
		case mPlay:
			switch (menuitem) {
				case miPlayCloseup:
					do_closeup_mi();
					break;
				case miPlayMove:
					query_position_modally(MOVE_TO_MODAL);
					break;
				case miPlaySetFormation:
					query_position_modally(SET_FORMATION_MODAL);
					break;
				case miPlayReturn:
					do_return(dside);
					break;
				case miPlayWake:
					do_wake(dside);
					break;
				case miPlaySleep:
					do_sleep(dside);
					break;
				case miPlayReserve:
					do_reserve(dside);
					break;
				case miPlayBuild:
					do_build(dside);
					break;
				case miPlayRepair:
					do_repair(dside);
					break;
				case miPlayAttack:
					query_position_modally(ATTACK_MODAL);
					break;
				case miPlayOverrun:
					do_overrun_mi();
					break;
				case miPlayFire:
					query_position_modally(FIRE_MODAL);
					break;
				case miPlayFireInto:
					query_position_modally(FIRE_INTO_MODAL);
					break;
				case miPlayDetonate:
					do_detonate_mi();
					break;
			}
			break;
		case mMore:
			switch (menuitem) {
				case miMoreTake:
					do_take_mi();
					break;
				case miMoreGive:
					beep();
					break;
				case miMoreEmbark:
					do_embark(dside);
					break;
				case miMoreDisembark:
					do_disembark(dside);
					break;
				case miMoreDrop:
					beep();
					break;
				case miMoreGiveUnit:
					/* has submenu mSides */
					break;
				case miMoreDetach:
					do_detach(dside);
					break;
				case miMoreDisband:
					do_disband(dside);
					break;
				case miMoreAddTerrain:
					query_position_modally(ADD_TERRAIN_MODAL);
					break;
				case miMoreRemoveTerrain:
					query_position_modally(REMOVE_TERRAIN_MODAL);
					break;
				case miMoreRename:
					do_name(dside);
					break;
				case miMoreAIControl:
					do_auto(dside);
					break;
			}
			break;
		case mSides:
			do_give_unit_mi(menuitem);
			break;
		case mSide:
			switch (menuitem) {
				case miSideCloseup:
					break;
				case miSideFinishedTurn:
					net_finish_turn(dside);
					break;
				case miSideMoveOnClick:
					moveonclick_mi();
					break;
				case miSideAutoSelect:
					autoselect_mi();
					break;
				case miSideAutoFinish:
					/* Toggle auto-finish for turns. */
					net_set_autofinish(dside, !dside->autofinish);
					break;
				case miSideSound:
					playsounds = !playsounds;
					ui_update_state();
					save_preferences();
					break;
				case miSideAutoResearch:
					if (numatypes > 0 && g_side_can_research()) {
						net_set_autoresearch(dside, !dside->autoresearch);
						draw_research_dialog(true);
					}
					break;
				case miSideSendMessage:
					do_message(dside);
					break;
				case miSideRename:
					side_rename_dialog(dside);
					break;
			}
			break;
		case 	mColors:
			if (menuitem <= numtotsides) {
				set_side_colors(menuitem - 1);
			/* - 2 because of Independents and separator line */
			} else if (menuitem <= numtotsides + FEATURES + 2) {
				 set_feature_color(menuitem - numtotsides - 2);
			} else {
			/* Pass terrain by sanitized name instead of number */
				GetItem(GetMenu(mColors), menuitem, daname);
				set_terrain_color(daname);
			}			
			force_overall_update();
			break;
		case mWindows:
			switch (menuitem) {
				case miWindowsGame:
					show_game_window();
					break;
				case miWindowsNotices:
					show_notice_window();
					break;
				case miWindowsHistory:
					show_history_window();
					break;
				case miWindowsConstruction:					
					show_construction_window();
					break;
				case miWindowsCommand:
					show_command_window();
					break;
				case miWindowsResearch:
					if (numatypes > 0) {
						/* Do side research if defined. */
						if (g_side_can_research())
							show_research_dialog();
						/* Else do unit based research. */
						else	side_research_dialog(dside, NULL, -1);
					}
					break;
				case miWindowsScores:
					show_scores_window();
					break;
#ifdef DESIGNERS
				case miWindowsDesign:
					show_design_window();
					break;
#endif
				/* should have agreements list etc handling here also */
				case miWindowsWorldMap:
					/* Create a new World Map if necessary. */
					if (!worldmap) {

						int p, mainwidth;

						get_main_screen_size(&mainwidth, 0);
						for (p = NUMPOWERS - 1; p > 0; p--) {
							if (area.width * hws[p] <= mainwidth / 4) { 
								break;
							}
						}
						create_map(p, 0);
						/* Break to avoid a crash if create_map failed! */
						if (worldmap == NULL)
						     break;
					}
					SelectTheWindow(worldmapwin);
					update_window(worldmapwin);
					break;
				case miWindowsNewList:
					create_list();
					break;
				case miWindowsNewMap:
					create_map(default_power, mapnum++);
					break;
				default:
					win = winmenuwins[menuitem - miWindowsFirst];
					if (win != nil) {
						SelectTheWindow(win);
						update_window(win);
					}
					break;
			}
			break;
		case mViewMap:
			if (map == NULL) break;
			switch (menuitem)  {
				case miViewCloser:
					magnify_map(map, 1);
					break;
				case miViewFarther:
					magnify_map(map, -1);
					break;
				case miViewPeople:
					toggle_map_people(map);
					break;
				case miViewControl:
					toggle_map_control(map);
					break;
				case miViewElevations:
					toggle_map_elevations(map);
					break;
				case miViewDaylight:
					toggle_map_lighting(map);
					break;
				case miViewCoverage:
					toggle_map_coverage(map);
					break;
				case miViewOffscreen:
					set_offscreen_buffers(map);
					break;
				case miViewMeridians:
					set_meridians(map);
					break;
				case miViewWorldMap:
					worldmap_dialog();
					break;
			}
			break;


		case mViewWeather:
			if (map == NULL) break;
			switch (menuitem)  {
				case miWeatherTemperature:
					toggle_map_temperature(map);
					break;
				case miWeatherWinds:
					toggle_map_winds(map);
					break;
				case miWeatherClouds:
					toggle_map_clouds(map);
					break;
			}
			break;
		case mViewAngles:
			if (map == NULL) break;
			switch (menuitem)  {
				case miAngle15:
					set_map_angle(map, 15);
					break;
				case miAngle30:
					set_map_angle(map, 30);
					break;
				case miAngle90:
					set_map_angle(map, 90);
					break;
			}
			break;
		case mViewText:
			if (map == NULL) break;
			switch (menuitem)  {
				case miTextUnitNames:
					toggle_map_names(map);
					break;
				case miTextFeatureNames:
					toggle_featurenames(map);
					break;
				case miTextOptimizeFonts:
					toggle_optimize_fonts(map);
					break;
				case miTextEraseNames:
					toggle_erase_names(map);
					break;
				case miTextDrawEmblems:
					toggle_map_draw_emblems(map);
					break;
			}
			break;

		case mViewGrids:
			if (map == NULL) break;
			switch (menuitem)  {
				case miViewGrid:
					toggle_map_grid(map);
					break;
				case miViewTopline:
					toggle_map_topline(map);
					break;
				case miViewTopunit:
					toggle_map_topunit(map);
					break;
				case miViewScrollBars:
					toggle_map_scrollbars(map);
					break;
				case miViewControlPanel:
					toggle_map_cpanel(map);
					break;
				case miViewOtherMaps:
					toggle_map_other_maps(map);
					break;
			}
			break;

		case mViewColors:
			if (map == NULL) break;
			switch (menuitem)  {
				case miSideColors:
					toggle_map_sidecolors(map);
					break;
				case miIconMasks:
					toggle_iconmasks(map);
					break;
				case miBoxMasks:
					toggle_boxmasks(map);
					break;
				case miTextMasks:
					toggle_textmasks(map);
					break;
				case miSolidColorTerrain:
					toggle_solid_color_terrain(map);
					break;
				case miBlinkingCurunit:
					toggle_blinking_curunit(map);
					break;
				case miSelectionMasks:
					toggle_selectionmasks(map);
					break;
			}
			break;

		case mViewBorders:
			if (map == NULL) break;
			switch (menuitem)  {
				case miFeatureBorders:
					toggle_featureborders(map);
					break;
				case miShoreLines:
					toggle_shorelines(map);
					break;
				case miSimpleBorders:
					toggle_simple_borders(map);
					break;
			}
			break;
		case mViewList:
			switch (menuitem)  {
				case miViewByType:
					set_list_sorting(list_from_window(topWindow), bytype, menuitem);
					break;
				case miViewByName:
					set_list_sorting(list_from_window(topWindow), byname, menuitem);
					break;
				case miViewBySide:
					set_list_sorting(list_from_window(topWindow), byside, menuitem);
					break;
				case miViewByActOrder:
					set_list_sorting(list_from_window(topWindow), byactorder, menuitem);
					break;
				case miViewByLocation:
					set_list_sorting(list_from_window(topWindow), bylocation, menuitem);
					break;
				case miViewCompleted:
					toggle_list_completed(list_from_window(topWindow));
					break;
				case miViewIncomplete:
					toggle_list_incomplete(list_from_window(topWindow));
					break;
				case miViewIconSize:
					toggle_list_large_icons(list_from_window(topWindow));
					break;
				case miListSideColors:
					toggle_list_sidecolors(list_from_window(topWindow));
					break;
				case miListDrawEmblems:
					toggle_list_draw_emblems(list_from_window(topWindow));
					break;
			}
			break;
		case mAITypes:
			switch (menuitem) {
				case 1:
					net_set_side_ai(dside, NULL);
					break;
				default:
					net_set_side_ai(dside, ai_type_name(menuitem - 1));
					break;
			}
			break;
		case mMagnifications:
			if (map == NULL) break;
			set_map_mag(map, menuitem - 1);
			break;
		case mMaterialTypes:
			if (map == NULL) break;
			toggle_map_materials(map, menuitem - 1);
			break;
		case mOptTerrainTypes:
			if (map == NULL) break;
			toggle_map_aux_terrain(map, aux_terrain_type_index[menuitem - 1]);
			break;
		case mPlanTypes:
			tmp_plan_type = PLAN_NONE;
			switch (menuitem)  {
				case miPlanTypeNone:
					tmp_plan_type = PLAN_NONE;
					break;
				case miPlanTypePassive:
					tmp_plan_type = PLAN_PASSIVE;
					break;
				case miPlanTypeDefensive:
					tmp_plan_type = PLAN_DEFENSIVE;
					break;
				case miPlanTypeExploratory:
					tmp_plan_type = PLAN_EXPLORATORY;
					break;
				case miPlanTypeOffensive:
					tmp_plan_type = PLAN_OFFENSIVE;
					break;
				case miPlanTypeColonizing:
					tmp_plan_type = PLAN_COLONIZING;
					break;
				case miPlanTypeImproving:
					tmp_plan_type = PLAN_IMPROVING;
					break;
				case miPlanTypeRandom:
					tmp_plan_type = PLAN_RANDOM;
					break;
			}
			do_plan_type_mi();
			break;
	}
	HiliteMenu(0);
}

/* Display the "About..." box. */

void
do_about_box()
{
	short ditem;
	Str255 tmpstr;
	WindowPtr win;
	PicHandle pic;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	win = GetNewDialog(dAbout, NULL, (DialogPtr) -1L);
	/* Fill in the kernel's version and copyright. */
	GetDItem(win, diAboutVersion, &itemtype, &itemhandle, &itemrect);
	c2p(version_string(), tmpstr);
	SetIText(itemhandle, tmpstr);
	GetDItem(win, diAboutCopyright, &itemtype, &itemhandle, &itemrect);
	c2p(copyright_string(), tmpstr);
	SetIText(itemhandle, tmpstr);
	/* Substitute a color picture if we've got a color/gray screen. */
	if (hasColorQD) {
		GetDItem(win, diAboutPicture, &itemtype, &itemhandle, &itemrect);
		if ((pic = (PicHandle) GetResource('PICT', pSplashColor)) != nil) {
			SetDItem(win, diAboutPicture, itemtype, (Handle) pic, &itemrect);
		}
	}
	ShowWindow(win);
	SelectWindow(win);
	draw_default_button(win, diAboutOK);
	SetCursor(&QD(arrow));
	ModalDialog(NULL, &ditem);
	/* Just return, no matter what input. */
	HideWindow(win);
	DisposeDialog(win);
	update_all_map_windows();
}

/* This routine does both "save" and "save as". */

void
save_the_game(int askname, int quitting)
{
	Point pnt;
	char namebuf[256];
	Str255 tmpstr;
    SFReply reply;

#ifdef DESIGNERS
	/* Do the selective save only if we're not shutting down Xconq. */
	if (is_designer(dside) && !quitting) {
		designer_save_dialog();
		return;
	}
#endif
	if (askname || cursavename == NULL) {
		if (cursavename == NULL)
		  cursavename = saved_game_filename();
		/* Collect the file and path to save to. */
		SetPt(&pnt, 100, 100);
		c2p(cursavename, tmpstr);
		SFPutFile(pnt, "\pSave game as:", tmpstr, /*(DlgHookProcPtr)*/ nil, &reply);
		if (!reply.good)
		  return;
		/* Make the location of the file be the current volume. */
		SetVol(reply.fName, reply.vRefNum);
		p2c(((char *) reply.fName), namebuf);
		cursavename = copy_string(namebuf);
	}
	SetCursor(*watchcursor);
	write_entire_game_state(cursavename);
	set_game_file_type(cursavename);
	SetCursor(&QD(arrow));
}

/*THPrint printrecordhandle = nil;*/

void
maybe_init_print()
{
/*	if (printrecordhandle == nil) {
		printrecordhandle = (THPrint) NewHandle(sizeof(TPrint));
		PrOpen();
		PrintDefault(printrecordhandle);
	} */
}

void
do_page_setup_mi()
{
	maybe_init_print();
/*	PrStlDialog(printrecordhandle); */
}

/* Handle printing.  What gets printed depends on which window is in front. */

static void
do_print_mi()
{
	Map *map;
	List *list;

	maybe_init_print();
/*	if (!PrJobDialog(printrecordhandle)) return; */
	if ((map = map_from_window(topWindow)) != NULL) {
		print_map(map);
	} else if ((list = list_from_window(topWindow)) != NULL) {
		print_list(list);
	} else {
		/* (should at least be able to print help) */
	}
}

static void
resign_the_game(int forced)
{
	Str255 tmpstr;

	sprintf(tmpbuf, "Other players");
	c2p(tmpbuf, tmpstr);
	ParamText(tmpstr, "\p", "\p", "\p");
	switch (CautionAlert(aResignGame, nil)) {
		case aiResignGameOK:
			forcedtoresign = forced;
			net_resign_game(dside, NULL);
			break;
		case aiResignGameWillingToDraw:
			net_set_willing_to_draw(dside, TRUE);
			break;
		case aiResignGameCancel:
			break;
	}
}

/* Attempt to quit. */

void
quit_the_game()
{
	int confirmresign = FALSE;

#ifdef DESIGNERS
	/* If we're designing, need only confirm the save before quitting;
	   no resignation requirement. */
	if (is_designer(dside)) {
		switch (CautionAlert(aDesignerQuitGame, nil)) {
			case aiDesignerQuitGameOK:
				SetCursor(*watchcursor);
				save_the_game(FALSE, TRUE);
				SetCursor(&QD(arrow));
				/* Fall through to exit. */
			case aiDesignerQuitGameDontSave:
				exit_macconq();
				break;
			case aiDesignerQuitGameCancel:
				break;
		}
		return;
	}
#endif /* DESIGNERS */
	if (endofgame) {
		/* Game is already over, nothing to save, just leave. */
		exit_macconq();
	} else if (!gamestatesafe) {
		switch (CautionAlert(aQuitGame, nil)) {
			case aiQuitGameOK:
				if (all_others_willing_to_save(dside)) {
					SetCursor(*watchcursor);
					save_the_game(FALSE, TRUE);
					SetCursor(&QD(arrow));
					exit_macconq();
				} else {
					net_set_willing_to_save(dside, TRUE);
					/* (should warn that not all were willing to save) */
				}
				break;
			case aiQuitGameDontSave:
				if (all_others_willing_to_quit(dside)) {
					net_set_willing_to_draw(dside, TRUE);
				} else {
					/* Can only get out by resigning. */
					confirmresign = TRUE;
				}
				break;
			case aiQuitGameCancel:
				break;
		}
	} else {
		/* (should still confirm that we're not avoiding our fate?) */
		exit_macconq();
	}
	if (confirmresign) {
		resign_the_game(TRUE);
	}
}

static void
te_cut(TEHandle hdl)
{
	if (ZeroScrap() == noErr) {
		TECut(hdl);
		if (TEToScrap() != noErr)
		  ZeroScrap();
	}
}

static void
te_copy(TEHandle hdl)
{
	if (ZeroScrap() == noErr) {
		TECopy(hdl);
		if (TEToScrap() != noErr)
		  ZeroScrap();
	}
}

static void
te_paste(TEHandle hdl)
{
	if (TEFromScrap() == noErr) {
		TEPaste(hdl);
	}
}

static void
do_select_all_mi()
{
	Unit *unit;

	if (topWindow == commandwin) {
		/* (should add this) */
	} else if (topWindow == constructionwin) {
		/* (should add this) */
	} else if (frontmap) {
		for_all_units(unit) {
			if (side_may_select(unit)) {
				select_unit_on_map(frontmap, unit);
			}
		}
		/* Do all the drawing at once. */
		draw_selections(frontmap);
	} else if (0 /* is list */) {
	}
}

static void
do_find_previous_mi()
{
	if (frontmap) {
		select_previous_unit(frontmap);
	}
}

static void
do_find_next_mi()
{
	if (frontmap) {
		select_next_mover(frontmap);
	}
}

static void
do_find_location_mi()
{
	int x, y, oldsx, oldsy;

	if (find_location_dialog(&x, &y)) {
		if (in_area(x, y)) {
			if (frontmap) {
				set_view_focus(frontmap->vp, x, y);
				/* (should make a common routine for this?) */
				if (!in_middle(frontmap, x, y)) {
					oldsx = frontmap->vp->sx;  
					oldsy = frontmap->vp->sy;
					set_view_focus(frontmap->vp, x, y);
					m_center_on_focus(frontmap);

					/* Scroll offscreen instead of forcing update */
					scroll_map_window(frontmap, 
								       frontmap->vp->sx - oldsx, 
								       frontmap->vp->sy - oldsy);
				}
			}
		} else {
			beep();
		}
	}
}

static void
do_find_unit_by_name_mi()
{
	int x, y;
	Unit *unit;
	
	if (find_unit_dialog(&unit)) {
		if (unit != NULL) {
			scroll_best_map_to_unit(unit, TRUE);
		} else {
			beep();
		}
	}
}

static int
find_location_dialog(int *xp, int *yp)
{
	short done = FALSE, ditem, rslt;
	DialogPtr win;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	rslt = FALSE;
	*xp = *yp = -1;
	win = GetNewDialog(dFindLocation, NULL, (DialogPtr) -1L);
	ShowWindow(win);
	while (!done) {
		draw_default_button(win, diFindLocationOK);
		SetCursor(&QD(arrow));
		ModalDialog(NULL, &ditem);
		switch (ditem) {
			case diFindLocationOK:
				GetDItem(win, diFindLocationText, &itemtype, &itemhandle, &itemrect);
				rslt = find_something(dside, get_string_from_item(itemhandle), 0, xp, yp, NULL);
				if (rslt)
				  done = TRUE;
				else
				  beep();
				break;
			case diFindLocationCancel:
				done = TRUE;
				break;
		}
	}
	DisposeDialog(win);
	update_all_map_windows();
	return rslt;
}

static int
worldmap_dialog(void)
{
	short done = FALSE, ditem;
	GrafPtr oldport;
	DialogPtr win;

	win = GetNewDialog(dWorldMap, NULL, (DialogPtr) -1L);
	GetPort(&oldport);	
	SetPort(win);
	ShowWindow(win);
	while (!done) {
		draw_default_button(win, diWorldMapOK);
		SetCursor(&QD(arrow));
		ModalDialog(NULL, &ditem);
		switch (ditem) {
			case diFindUnitOK:
				done = TRUE;
				break;
		}
	}
	DisposeDialog(win);
	SetPort(oldport);
	update_all_map_windows();
}

static int
find_unit_dialog(Unit **unitp)
{
	short done = FALSE, ditem, rslt;
	DialogPtr win;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	rslt = FALSE;
	*unitp = NULL;
	win = GetNewDialog(dFindUnit, NULL, (DialogPtr) -1L);
	ShowWindow(win);
	while (!done) {
		draw_default_button(win, diFindUnitOK);
		SetCursor(&QD(arrow));
		ModalDialog(NULL, &ditem);
		switch (ditem) {
			case diFindUnitOK:
				GetDItem(win, diFindUnitText, &itemtype, &itemhandle, &itemrect);
				rslt = find_something(dside, get_string_from_item(itemhandle), 1, NULL, NULL, unitp);
				if (rslt)
				  done = TRUE;
				else
				  beep();
				break;
			case diFindUnitCancel:
				done = TRUE;
				break;
		}
	}
	DisposeDialog(win);
	update_all_map_windows();
	return rslt;
}

/* (should make generic) */
static int
find_something(Side *side, char *str, int findunit, int *xp, int *yp, Unit **unitp)
{
	Unit *unit;
	Feature *feature;

	if (empty_string(str))
	  return FALSE;
	if (findunit) {
		/* Thumb through the side's own units first. */
		for_all_side_units(side, unit) {
			if (in_play(unit)
				&& !empty_string(unit->name)
				&& strcmp(str, unit->name) == 0) {
				*unitp = unit;
				return TRUE;
			}
		}
		/* Look for other units that this side might know about. */
		for_all_units(unit) {
			if (in_play(unit)
				&& !empty_string(unit->name)
				&& strcmp(str, unit->name) == 0
				&& side_sees_image(side, unit)) {
				*unitp = unit;
				return TRUE;
			}
		}
	} else {
		if (isdigit(*str)) {
			if (sscanf(str, "%d,%d", xp, yp) == 2
				&& in_area(*xp, *yp))
			  return TRUE;
		} else {
			/* Look for a geographical feature. */
			/* Exact matches first, then approximate. */
    		for_all_features(feature) {
				if (feature->name && strcmp(feature->name, str) == 0) {
					*xp = feature->x;  *yp = feature->y;
					return TRUE;
				}
    		}
    		for_all_features(feature) {
				if (feature->name && strstr(feature->name, str) == 0) {
					*xp = feature->x;  *yp = feature->y;
					return TRUE;
				}
    		}
		}
	}
	return FALSE;
}

static void
do_find_selected_mi()
{
	List *list;
	UnitCloseup *closeup;
	
	if ((list = list_from_window(topWindow)) != NULL) {
		scroll_to_selected_unit_in_list(list);
	} else if (frontmap) {
		int i;
		Unit *unit;

		/* Scroll to the first valid selected unit we find. */
		for (i = 0; i < frontmap->numselections; ++i) {
			unit = frontmap->selections[i];
			if (in_play(unit)) {
				scroll_to_unit(frontmap, unit);
				return;
			}
		}
		beep();
	} else if ((closeup = unit_closeup_from_window(topFloat)) != NULL) {
		if (closeup->unit != NULL)
		  scroll_best_map_to_unit(closeup->unit, TRUE);
	} else if (constructionwin == topWindow) {
		scroll_to_selected_construction_unit();
	} else {
		/* nothing to do */
	}
}

/* Menu items/commands for unit play action. */

void
apply_to_all_selected(int (*fn)(Unit *unit), int beepfailure)
{
	int i, rslt, numcould = 0, numnot = 0;
	Map *map;
	List *list;  
	UnitCloseup *closeup;
	Unit *unit;

	if (fn == NULL)
	  return;
	if (frontmap) {
		for (i = 0; i < frontmap->numselections; ++i) {
			unit = frontmap->selections[i];
			/* Don't apply to selected units that we don't control. */
			if (in_play(unit) && side_controls_unit(dside, unit)) {
				rslt = (*fn)(unit);
				if (rslt)
				  ++numcould;
				else
				  ++numnot;
			}
		}
	} else if ((list = list_from_window(topWindow)) != NULL) {
		if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
			rslt = (*fn)(unit);
			if (rslt)
			  ++numcould;
			else
			  ++numnot;
		}
	} else if ((closeup = unit_closeup_from_window(topFloat)) != NULL) {
		unit = closeup->unit;
		/* Don't apply to units that we don't control. */
		if (side_controls_unit(dside, unit)) {
			rslt = (*fn)(unit);
			if (rslt)
			  ++numcould;
			else
			  ++numnot;
		}
	} else if (maplist != NULL) {
		map = maplist;
		for (i = 0; i < map->numselections; ++i) {
			unit = map->selections[i];
			/* Don't apply to selected units that we don't control. */
			if (in_play(unit) && side_controls_unit(dside, unit)) {
				rslt = (*fn)(unit);
				if (rslt)
				  ++numcould;
				else
				  ++numnot;
			}
		}
	}
	/* If everybody that was asked to do this couldn't, beep once. */
	if (beepfailure && numcould == 0 && numnot > 0)
	  beep();
}

void		/* Now declared extern. */
do_closeup_mi()
{
	UnitCloseup *unitcloseup;
	Unit *unit;
	List *list;  
	int i;
	
	/* First check if we have selected a unit in the front list. */
	if ((list = list_from_window(topWindow)) != NULL) {
		if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
			scroll_to_selected_unit_in_list(list);
			show_unit_closeup(unit);
			return;
		}
	}
	/* If not, check for selections in the front map. */
	if (frontmap && frontmap->numselections) {
		for (i = 0; i < frontmap->numselections; ++i) {
			if ((unit = frontmap->selections[i]) != NULL) {
				show_unit_closeup(unit);
			}
		}
		return;
	}
	/* Not sure what the point is of this, but let's do it anyway ... */
	if ((unitcloseup = unit_closeup_from_window(topFloat)) != NULL) {
		if ((unit = unitcloseup->unit) != NULL) {
			force_update(unitcloseup->window);
		}
	}
}

static void
do_overrun_mi()
{
	/* (should loop until mouse clicked in map) */
	beep();
}

static void
do_detonate_mi()
{
	do_detonate(dside);
}

static void
do_give_unit_mi(int mi)
{
	/* Menu items start at 1, not 0. */
	Side *side = side_n(mi - 1);
	/* note that side_n returns NULL for mi == numsides */

    tmpcmdside = side;	
	apply_to_all_selected(do_one_give_unit, TRUE);
}

static void
moveonclick_mi()
{
	if (frontmap) {
		frontmap->moveonclick = !frontmap->moveonclick;
		/* (should force updates of map windows to reflect?) */
		/* Necessary or the control panel will get out of sync! */
		draw_control_panel(frontmap);
	} else {
		defaultmoveonclick = !defaultmoveonclick;
	}
}

void
do_plan_type_mi()
{
	apply_to_all_selected(do_one_plan_type, TRUE);	
}

static int
do_one_plan_type(Unit *unit)
{
    int newval;

	if (unit->plan) {
		newval = tmp_plan_type;
		net_set_unit_plan_type(dside, unit, newval);
	}
	return TRUE;
}

static void
do_take_mi()
{
	do_take(dside);
}

static void
autoselect_mi()
{
	if (frontmap)
		frontmap->autoselect = !frontmap->autoselect;
	else 	defaultautoselect = !defaultautoselect;
}

static void
adjust_menu_item(MenuHandle menu, int item, int value)
{
	if (value)
	  EnableItem(menu, item);
	else
	  DisableItem(menu, item);
}

/* The state of menu items changes to reflect selected units, etc. */

/* Note: it is now the sole responsibility of adjust_menus to decide what commands
should be accesible and when. All enabled map commands will be executed using the 
frontmap, even if it is not in the topWIndow. */

void
adjust_menus()
{
	int i, m, t, numwins, menus_useful, numitems, text_win, has_text, offset;
	MenuHandle menu, menu2;
	unsigned char keyMap[16];
	int optionKey;
	Map *map;
	List *list;
	UnitCloseup *closeup;
	Unit *unit;
	WindowPtr win;

	/* Access world map if option key is down. */	
	GetKeys((GETKEYS_ARG_TYPE) keyMap);
	optionKey = keyMap[0x3A >> 3] >> (0x3A & 7) & 1;
	if (optionKey && worldmap) {
		win = worldmapwin;
	} else	win = topWindow;

	map = map_from_window(win);
	list = list_from_window(win);
	
	/* This is kind of problematic since commands referring either to the
	topWindow or the topFloat now may appear in the same menu. Hopefully,
	it will not cause any problems, but if it does one would have to consider
	removing all menu commads belonging to closeups. */
	closeup = unit_closeup_from_window(topFloat);

	menus_useful =
		(gamedefined
		 && ((!beforestart && !endofgame)
		 	 || (gameinited && is_designer(dside))));
	/* Certain menus need to be built after the game is running. */
	if (menus_useful) {
		build_material_type_menu();
		build_side_menu();
		build_ai_type_menu();
	}
	menu = GetMHandle(mApple);
	if (menu != nil) {
		adjust_menu_item(menu, miAppleInstructions, gamedefined);
	}
	menu = GetMHandle(mFile);
	if (menu != nil) {
		/* Availability of file menu items depends on whether we're in a game. */
		adjust_menu_item(menu, miFileNew, !gamedefined);
		adjust_menu_item(menu, miFileOpen, !gamedefined);

		/* Always disable defunct connect item for now. */
		adjust_menu_item(menu, miFileConnect, FALSE);
/*		adjust_menu_item(menu, miFileConnect, !gamedefined);		*/

		adjust_menu_item(menu, miFileClose, (win != NULL));
		adjust_menu_item(menu, miFileSave, menus_useful);
		adjust_menu_item(menu, miFileSaveAs, menus_useful);
		adjust_menu_item(menu, miFilePrintWindow, (map != NULL || list != NULL));
		adjust_menu_item(menu, miFileResign, menus_useful && dside->ingame);
	}
	menu = GetMHandle(mEdit);
	if (menu != nil) {
		/* Edit menu is always available, but individual items may be disabled. */
		adjust_menu_item(menu, miEditUndo, FALSE);
		text_win = has_text = FALSE;
		if (win && win == commandwin) {
			text_win = TRUE;
			has_text = ((*command_text)->selStart < (*command_text)->selEnd);
		} else if (win && win == constructionwin) {
			text_win = TRUE;
			has_text = ((*run_length_text)->selStart < (*run_length_text)->selEnd);
		}
		adjust_menu_item(menu, miEditCut, has_text);
		adjust_menu_item(menu, miEditCopy, has_text);
		adjust_menu_item(menu, miEditPaste, (text_win && (GetScrap(nil, 'TEXT', (long *) &offset) > 0)));
		adjust_menu_item(menu, miEditClear, has_text);
		adjust_menu_item(menu, miEditSelectAll, (map != NULL || list != NULL || has_text));
		if (menus_useful) {
#ifdef DESIGNERS
			CheckItem(menu, miEditDesign, is_designer(dside));
#else
			DisableItem(menu, miEditDesign);
#endif /* DESIGNERS */
		}
	}
	menu = GetMHandle(mFind);
	if (menu != nil) {
		if (gameinited) {
			EnableItem(menu, 0);
			adjust_menu_item(menu, miFindPrevious, menus_useful);
			adjust_menu_item(menu, miFindNext, menus_useful);
			DisableItem(menu, miFindNextOccupant);
			adjust_menu_item(menu, miFindLocation, menus_useful);
			adjust_menu_item(menu, miFindUnitByName, menus_useful);
			adjust_menu_item(menu, miFindDistance, menus_useful);
			adjust_menu_item(menu, miFindSelected, (map != NULL || list != NULL || closeup != NULL || constructionwin == win));
		} else {
			/* We're not even in a game yet, turn entire menu off. */
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mPlay);
	menu2 = GetMHandle(mMore);
	if (menu != nil && menu2 != nil) {
		if (gameinited) {
			EnableItem(menu, 0);
			/* Disable everything first, then selectively re-enable. */
			DisableItem(menu, miPlayCloseup);
			DisableItem(menu, miPlayCityDialog);
			DisableItem(menu, miPlayMove);
			DisableItem(menu, miPlaySetFormation);
			DisableItem(menu, miPlayReturn);
			DisableItem(menu, miPlayWake);
			DisableItem(menu, miPlaySleep);
			DisableItem(menu, miPlayReserve);
			DisableItem(menu, miPlayDelay);
			DisableItem(menu, miPlayBuild);
			DisableItem(menu, miPlayRepair);
			DisableItem(menu, miPlayAttack);
			DisableItem(menu, miPlayOverrun);
			DisableItem(menu, miPlayFire);
			DisableItem(menu, miPlayFireInto);
			DisableItem(menu, miPlayDetonate);
			EnableItem(menu2, 0);
			DisableItem(menu2, miMoreGive);
			DisableItem(menu2, miMoreTake);
			DisableItem(menu2, miMoreEmbark);
			DisableItem(menu2, miMoreDisembark);
			DisableItem(menu2, miMoreDrop);
			DisableItem(menu2, miMoreGiveUnit);
			DisableItem(menu2, miMoreDetach);
			DisableItem(menu2, miMoreDisband);
			DisableItem(menu2, miMoreAddTerrain);
			DisableItem(menu2, miMoreRemoveTerrain);
			DisableItem(menu2, miMorePlanTypes);
			DisableItem(menu2, miMoreAIControl);
			DisableItem(menu2, miMoreRename);
			/* Note that command enabling is accumulative for all units; if at least
			   one of the selected units can do something, the menu item turns on. */
			if (map != NULL) {
				for (i = 0; i < map->numselections; ++i) {
					if ((unit = map->selections[i]) != NULL) {
						enable_commands_for_unit(menu, menu2, unit);
					}
				}
			} else if (list != NULL) {
				if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
					enable_commands_for_unit(menu, menu2, unit);
				}
			} else if (closeup != NULL) {
				/* Don't enable commands for enemy closeups. */
				if ((unit = closeup->unit) != NULL
				    && side_controls_unit(dside, unit)) {
					enable_commands_for_unit(menu, menu2, unit);
				}
			}
		} else {
			/* We're not even in a valid game state yet, turn entire menus off. */
			DisableItem(menu, 0);
			DisableItem(menu2, 0);
		}
	}
	menu = GetMHandle(mSide);
	if (menu != nil) {
		if (menus_useful) {
			EnableItem(menu, 0);
			CheckItem(menu, miSideMoveOnClick,
					  (map ? map->moveonclick : defaultmoveonclick));
			CheckItem(menu, miSideAutoSelect,
					  (map ? map->autoselect : defaultautoselect));
			CheckItem(menu, miSideAutoFinish, dside->autofinish);
			CheckItem(menu, miSideSound, playsounds);
			if (numatypes > 0
	    		    && g_side_can_research()) {
				EnableItem(menu, miSideAutoResearch);
				CheckItem(menu, miSideAutoResearch, dside->autoresearch);
			} else {
				DisableItem(menu, miSideAutoResearch);
			}
			if (dside->nameslocked) {
				DisableItem(menu, miSideRename);
			} else {
				EnableItem(menu, miSideRename);
			}
		} else {
			/* We're not even in a game yet, turn entire menu off. */
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mWindows);
	if (menu != nil) {
		if (gameinited) {
			EnableItem(menu, 0);
			/* Most window types are always enabled. */
			CheckItem(menu, miWindowsGame,
				(gamewin && ((WindowPeek) gamewin)->visible));
			CheckItem(menu, miWindowsNotices,
				(noticewin && ((WindowPeek) noticewin)->visible));
			CheckItem(menu, miWindowsHistory,
				(historywin && ((WindowPeek) historywin)->visible));
			CheckItem(menu, miWindowsCommand,
				(commandwin && ((WindowPeek) commandwin)->visible));
			if (any_construction_possible()) {
				EnableItem(menu, miWindowsConstruction);
				CheckItem(menu, miWindowsConstruction,
					(constructionwin && ((WindowPeek) constructionwin)->visible));
			} else {
				DisableItem(menu, miWindowsConstruction);
			}
			DisableItem(menu, miWindowsResearch);
			if (numatypes > 0) {
				if (g_side_can_research()) {
					EnableItem(menu, miWindowsResearch);
				} else for_all_side_units(dside, unit) {
				if (u_can_research(unit->type)) {
					EnableItem(menu, miWindowsResearch);
					break;
				}
			}
			}
			CheckItem(menu, miWindowsResearch,
				(researchwin && ((WindowPeek) researchwin)->visible));
			CheckItem(menu, miWindowsScores,
				(scoreswin && ((WindowPeek) scoreswin)->visible));
#ifdef DESIGNERS
			if (is_designer(dside)) {
				EnableItem(menu, miWindowsDesign);
				CheckItem(menu, miWindowsDesign,
					(designwin && ((WindowPeek) designwin)->visible));
			} else	{
				DisableItem(menu, miWindowsDesign);
				CheckItem(menu, miWindowsDesign, false);
			}
#else
			DisableItem(menu, miWindowsDesign);
			CheckItem(menu, miWindowsDesign, false);
#endif /* DESIGNERS */
			CheckItem(menu, miWindowsWorldMap, worldmapwin && worldmapwin == win);
			/* Go through all the user-added windows. */
			numwins = CountMItems(menu) - miWindowsFirst + 1;		
			/* (miWindowsFirst equals the number of windows + 1) */
			for (i = 0; i < numwins; ++i) {
				CheckItem(menu, i + miWindowsFirst, (winmenuwins[i] == win));
			}
		} else {
			/* We're not even in a game yet, turn entire menu off. */
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mColors);
	if (menu != nil) {
		EnableItem(menu, 0);

	}
	/* If a map window is frontmost, install and adjust the map view menu. */
	if (map != NULL) {
		/* Delete the list view menu if that's what's installed currently. */
		menu = GetMHandle(mViewList);
		if (menu != nil)
		  DeleteMenu(mViewList);
		/* Make sure the map view menu is installed (is always at the end). */
		InsertMenu(mapviewmenu, 0);
		menu = GetMHandle(mViewMap);
		if (menu != nil) {
			EnableItem(menu, 0);
			if (map->vp->power == 0) {
				DisableItem(menu, miViewFarther);
			} else {
				EnableItem(menu, miViewFarther);
			}
			if (map->vp->power == NUMPOWERS-1) {
				DisableItem(menu, miViewCloser);
			} else {
				EnableItem(menu, miViewCloser);
			}
			EnableItem(menu, miViewOffscreen);
			if (worldmap) {
				EnableItem(menu, miViewWorldMap);
			} else {
				DisableItem(menu, miViewWorldMap);
			}
			if (people_sides_defined()) {
				EnableItem(menu, miViewPeople);
				CheckItem(menu, miViewPeople, map->vp->draw_people);
			} else {
				DisableItem(menu, miViewPeople);
			}
			if (control_sides_defined()) {
				EnableItem(menu, miViewControl);
				CheckItem(menu, miViewControl, map->vp->draw_control);
			} else {
				DisableItem(menu, miViewControl);
			}
			if (elevations_defined()) {
				EnableItem(menu, miViewElevations);
				CheckItem(menu, miViewElevations, map->vp->draw_elevations);
			} else {
				DisableItem(menu, miViewElevations);
			}
			if (temperatures_defined() || winds_defined() || clouds_defined()) {
				EnableItem(menu, miViewWeather);
			} else {
				DisableItem(menu, miViewWeather);
			}
			if (nummtypes > 0) {
				EnableItem(menu, miViewMaterials);
				/* (should do checkmark if anything in submenu is on) */
			} else {
				DisableItem(menu, miViewMaterials);
			}
			if (numbordtypes + numconntypes + numcoattypes > 0) {
				EnableItem(menu, miViewTerrain);
			} else {
				DisableItem(menu, miViewTerrain);
			}
			if (world.daylength != 1) {
				EnableItem(menu, miViewDaylight);
				CheckItem(menu, miViewDaylight, map->vp->draw_lighting);
			} else {
				DisableItem(menu, miViewDaylight);
			}
			if (dside->coverage) {
				EnableItem(menu, miViewCoverage);
				CheckItem(menu, miViewCoverage, map->vp->draw_cover);
			} else {
				DisableItem(menu, miViewCoverage);
			}
			menu = GetMHandle(mViewWeather);
			if (menu != nil) {
				EnableItem(menu, 0);
				if (temperatures_defined()) {
					EnableItem(menu, miWeatherTemperature);
					CheckItem(menu, miWeatherTemperature, map->vp->draw_temperature);
				} else {
					DisableItem(menu, miWeatherTemperature);
				}
				if (winds_defined()) {
					EnableItem(menu, miWeatherWinds);
					CheckItem(menu, miWeatherWinds, map->vp->draw_winds);
				} else {
					DisableItem(menu, miWeatherWinds);
				}
				if (clouds_defined()) {
					EnableItem(menu, miWeatherClouds);
					CheckItem(menu, miWeatherClouds, map->vp->draw_clouds);
				} else {
					DisableItem(menu, miWeatherClouds);
				}
			}
		}
	} else if (list != NULL) {
		/* Do the list view menu similarly. */
		menu = GetMHandle(mViewMap);
		if (menu != nil)
		  DeleteMenu(mViewMap);
		/* Make sure the menu is actually installed (is always at the end). */
		InsertMenu(listviewmenu, 0);
		menu = GetMHandle(mViewList);
		if (menu != nil) {
			EnableItem(menu, 0);
			if (1 /* at least one unit in list */) {
				EnableItem(menu, miViewByType);
				CheckItem(menu, miViewByType, (list->mainsortmi == miViewByType));
				EnableItem(menu, miViewByName);
				CheckItem(menu, miViewByName, (list->mainsortmi == miViewByName));
				EnableItem(menu, miViewBySide);
				CheckItem(menu, miViewBySide, (list->mainsortmi == miViewBySide));
				EnableItem(menu, miViewByActOrder);
				CheckItem(menu, miViewByActOrder, (list->mainsortmi == miViewByActOrder));
				EnableItem(menu, miViewByLocation);
				CheckItem(menu, miViewByLocation, (list->mainsortmi == miViewByLocation));
				/* should mark the secondary sort? */
				EnableItem(menu, miViewCompleted);
				CheckItem(menu, miViewCompleted, list->completed_units);
				EnableItem(menu, miViewIncomplete);
				CheckItem(menu, miViewIncomplete, list->incomplete_units);
				EnableItem(menu, miViewWithTransport);
				DisableItem(menu, miViewWithCommander);
				EnableItem(menu, miViewIconSize);
				CheckItem(menu, miViewIconSize, list->largeicons);
				EnableItem(menu, miListSideColors);
				CheckItem(menu, miListSideColors, list->sidecolors);
				EnableItem(menu, miListDrawEmblems);
				CheckItem(menu, miListDrawEmblems, list->draw_emblems);
			} else {
				DisableItem(menu, miViewByType);
				DisableItem(menu, miViewByName);
				DisableItem(menu, miViewBySide);
				DisableItem(menu, miViewByActOrder);
				DisableItem(menu, miViewByLocation);
				DisableItem(menu, miViewWithTransport);
				DisableItem(menu, miViewWithCommander);
				DisableItem(menu, miViewIconSize);
				DisableItem(menu, miListSideColors);
				DisableItem(menu, miListDrawEmblems);
			}
		}
	} else {
		/* For any other window, disable any or all of the view menus, as needed. */
		menu = GetMHandle(mViewList);
		if (menu != nil)
		  DisableItem(menu, 0);
		menu = GetMHandle(mViewMap);
		if (menu != nil)
		  DisableItem(menu, 0);
	}
	menu = GetMHandle(mMagnifications);
	if (menu != nil) {
		/* Always on. */
		EnableItem(menu, 0);
		if (map != NULL) {
			for (i = 0; i < NUMPOWERS; ++i) {
				CheckItem(menu, i + 1, (i == map->vp->power));
			}
		}
	}
	menu = GetMHandle(mMaterialTypes);
	if (menu != nil) {
		/* Always on, if any material types defined. */
		if (nummtypes > 0) {
			EnableItem(menu, 0);
			if (map != NULL) {
				for_all_material_types(m) {
					if (any_cell_materials_defined() && cell_material_defined(m)) {
						EnableItem(menu, m + 1);
						CheckItem(menu, m + 1, map->vp->draw_materials[m]);
					} else {
					    CheckItem(menu, i, FALSE);
						DisableItem(menu, m + 1);
					}
				}
			}
		} else {
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mOptTerrainTypes);
	if (menu != nil) {
		if (any_aux_terrain_defined()) {
			EnableItem(menu, 0);
			if (map != NULL) {
				numitems = CountMItems(menu);
				for (i = 1; i <= numitems; ++i) {
					t = aux_terrain_type_index[i - 1];
					if (any_aux_terrain_defined() && aux_terrain_defined(t)) {
						EnableItem(menu, i);
					    CheckItem(menu, i, map->vp->draw_aux_terrain[t]);
					} else {
					    CheckItem(menu, i, FALSE);
						DisableItem(menu, i);
					}
				}
			}
		} else {
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mAITypes);
	if (menu != nil) {
		/* Always on. */
		EnableItem(menu, 0);
		CheckItem(menu, 1, (!side_has_ai(dside)));
		numitems = CountMItems(menu);
		for (i = 2; i <= numitems; i++)
			CheckItem(menu, i, side_has_ai(dside) && dside->aitype == (i - 1));
	}
	menu = GetMHandle(mViewText);
	if (menu != nil && map != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miTextUnitNames);
		CheckItem(menu, miTextUnitNames, ( map->vp->draw_names));
		EnableItem(menu, miTextFeatureNames);
		CheckItem(menu, miTextFeatureNames, (map->featurenames));
		EnableItem(menu, miTextOptimizeFonts);
		CheckItem(menu, miTextOptimizeFonts, (map->optimize_fonts));
		EnableItem(menu, miTextEraseNames);
		CheckItem(menu, miTextEraseNames, (map->erase_names));
		EnableItem(menu, miTextDrawEmblems);
		CheckItem(menu, miTextDrawEmblems, (map->draw_emblems));
	}

	menu = GetMHandle(mViewGrids);
	if (menu != nil && map != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miViewGrid);
		CheckItem(menu, miViewGrid, map->vp->draw_grid);
		EnableItem(menu, miViewTopline);
		CheckItem(menu, miViewTopline, (map->toplineh > 0));
		EnableItem(menu, miViewTopunit);
		CheckItem(menu, miViewTopunit, (map->topunith > 0));
		EnableItem(menu, miViewScrollBars);
		CheckItem(menu, miViewScrollBars, (map->sbarwid > 0));
		EnableItem(menu, miViewControlPanel);
		CheckItem(menu, miViewControlPanel, (map->conw > 0));
		if (nummaps > 1) {
			EnableItem(menu, miViewOtherMaps);
			CheckItem(menu, miViewOtherMaps, map->vp->draw_other_maps);
		} else {
			DisableItem(menu, miViewOtherMaps);
		}

	}

	menu = GetMHandle(mViewColors);
	if (menu != nil && map != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miSideColors);
		CheckItem(menu, miSideColors, map->sidecolors);
		EnableItem(menu, miIconMasks);
		CheckItem(menu, miIconMasks, map->iconmasks);
		EnableItem(menu, miBoxMasks);
		CheckItem(menu, miBoxMasks, map->boxmasks);
		EnableItem(menu, miTextMasks);
		CheckItem(menu, miTextMasks, map->textmasks);
		EnableItem(menu, miSolidColorTerrain);
		CheckItem(menu, miSolidColorTerrain, map->solid_color_terrain);
		EnableItem(menu, miBlinkingCurunit);
		CheckItem(menu, miBlinkingCurunit, map->blinking_curunit);
		EnableItem(menu, miSelectionMasks);
		CheckItem(menu, miSelectionMasks, map->selectionmasks);
	}

	menu = GetMHandle(mViewBorders);
	if (menu != nil && map != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miFeatureBorders);
		CheckItem(menu, miFeatureBorders, map->featureborders);
		EnableItem(menu, miShoreLines);
		CheckItem(menu, miShoreLines, map->shorelines);
		EnableItem(menu, miSimpleBorders);
		CheckItem(menu, miSimpleBorders, map->simple_borders);
	}
	/* Everything has been tweaked, redraw the menu bar. */
	DrawMenuBar();
}

/* Tweak the command menu according to what the unit can do. */
/* (some of these should have the menu text tweaked also, terms weird sometimes) */

int any_transport_here(Side *side, Unit *unit, int x, int y);

int
any_transport_here(side, unit, x, y)
Side *side;
Unit *unit;
int x, y;
{
	Unit *unit2;

	for_all_stack(x, y, unit2) {
		if (unit2 != unit
			&& unit2 != unit->transport
			&& trusted_side(side, unit2->side)
			&& can_occupy(unit, unit2)
			) {
			return TRUE;
		}
	}
	return FALSE;
}

static void
enable_commands_for_unit(MenuHandle menu, MenuHandle menu2, Unit *unit)
{
	int u = unit->type, sn;
	Side *side2;
	MenuHandle menu3;

	/* Might get dead units in here, filter them out. */
	if (!in_play(unit))
	  return;
	/* If we can select the unit at all, we can always get a closeup of it. */
	EnableItem(menu, miPlayCloseup);
	/* (how to do checkmarks if multiple units selected? use '-' as per HIG) */
	CheckItem(menu, miPlayCloseup, (find_unit_closeup(unit) != NULL));
	/* If we don't actually have any control over the unit, or the game is over,
	   nothing more to do. */

	/* Enable city dialog for advanced unit. */
	if (u_advanced(unit->type))
		EnableItem(menu, miPlayCityDialog);

	if (!side_controls_unit(dside, unit) || endofgame)
	  return;
	if (can_move_at_all(unit)) {
		EnableItem(menu, miPlayMove);
		if (nummtypes > 0) {
			/* also check that unit carries any material and for places to return to */
			EnableItem(menu, miPlayReturn);
		}
	}
	if (unit->plan) {
		EnableItem(menu, miPlaySetFormation);
		EnableItem(menu, miPlayWake);
		CheckItem(menu, miPlayWake, !unit->plan->asleep);
		EnableItem(menu, miPlaySleep);
		CheckItem(menu, miPlaySleep, unit->plan->asleep);
		EnableItem(menu, miPlayReserve);
		CheckItem(menu, miPlayReserve, unit->plan->reserve);
		EnableItem(menu, miPlayDelay);
		CheckItem(menu, miPlayDelay, unit->plan->delayed);
		EnableItem(menu2, miMorePlanTypes);
		EnableItem(menu2, miMoreAIControl);
		CheckItem(menu2, miMoreAIControl, unit->plan->aicontrol);
		menu3 = GetMHandle(mPlanTypes);
		if (menu3 != nil) {
			EnableItem(menu3, 0);
			CheckItem(menu3, miPlanTypeNone, (unit->plan->type == PLAN_NONE));
			CheckItem(menu3, miPlanTypePassive, (unit->plan->type == PLAN_PASSIVE));
			CheckItem(menu3, miPlanTypeDefensive, (unit->plan->type == PLAN_DEFENSIVE));
			CheckItem(menu3, miPlanTypeExploratory, (unit->plan->type == PLAN_EXPLORATORY));
			CheckItem(menu3, miPlanTypeOffensive, (unit->plan->type == PLAN_OFFENSIVE));
			CheckItem(menu3, miPlanTypeRandom, (unit->plan->type == PLAN_RANDOM));
			CheckItem(menu3, miPlanTypeColonizing, (unit->plan->type == PLAN_COLONIZING));
			CheckItem(menu3, miPlanTypeImproving, (unit->plan->type == PLAN_IMPROVING));
		}
	}
	if ((can_create(unit) || can_complete(unit))
		&& (unit->transport == NULL
			|| !completed(unit->transport)
			|| uu_occ_can_build(unit->transport->type, u))) {
		EnableItem(menu, miPlayBuild);
	}
	if (can_repair(unit)) {
		EnableItem(menu, miPlayRepair);
	}
	if (can_attack(unit)) {
		EnableItem(menu, miPlayAttack);
		EnableItem(menu, miPlayOverrun);
	}
	if (can_fire(unit)) {
		EnableItem(menu, miPlayFire);
		EnableItem(menu, miPlayFireInto);
	}
	if (can_detonate(unit)) {
		EnableItem(menu, miPlayDetonate);
	}
	if (nummtypes > 0 /* (should also test unit capacity) */) {
		EnableItem(menu2, miMoreGive);
		EnableItem(menu2, miMoreTake);
	}
	if (any_transport_here(dside, unit, unit->x, unit->y)) {
		EnableItem(menu2, miMoreEmbark);
	}
	if (unit->transport != NULL) {
		EnableItem(menu2, miMoreDisembark);
	}
	/* (should decide what to do about Drop) */
	if (num_sides_allowed(u) > 1 || is_designer(dside)) {
		EnableItem(menu2, miMoreGiveUnit);
	}
	if (side_can_disband(dside, unit)) {
		EnableItem(menu2, miMoreDisband);
	}
	if (u_parts(u) > 1 && unit->hp > 1) {
		EnableItem(menu2, miMoreDetach);
	}
	if (can_add_terrain(unit)) {
		EnableItem(menu2, miMoreAddTerrain);
	}
	if (can_remove_terrain(unit)) {
		EnableItem(menu2, miMoreRemoveTerrain);
	}
	if (1 /* !unitnameslocked */) {
		EnableItem(menu2, miMoreRename);
	}
	/* Adjust the Find menu. */
	menu3 = GetMHandle(mFind);
	if (menu3 != nil) {
		if (gameinited) {
			adjust_menu_item(menu3, miFindNextOccupant, (unit->occupant || unit->nexthere || unit->transport));
		}
	}
	/* Adjust the give unit menu. */
	menu3 = GetMHandle(mSides);
	if (menu3 != nil) {
		if (num_sides_allowed(u) > 1 || is_designer(dside)) {
			EnableItem(menu3, 0);
			for_all_sides(side2) {
				if (unit_allowed_on_side(unit, side2)
					&& u_acp_to_change_side(unit->type)
					&& unit->side != side2) {
					/* Menu item numbers start with 1. */
					EnableItem(menu3, side_number(side2) + 1);
				} else {
					DisableItem(menu3, side_number(side2) + 1);
				}
			}
		} else {
			DisableItem(menu3, 0);
		}
	}
}

/* Dialog that sets the size of the offscreen scrolling buffers. */

void
set_offscreen_buffers(Map *map)
{
	short ditem, itemtype, done = FALSE;
	long *itemnum = 0;
	Handle itemhandle;  
	Rect itemrect;
	Str255 tmpstr;
	DialogPtr win;
	GrafPtr oldport;

	win = GetNewDialog(dOffscreen, NULL, (DialogPtr) -1);
	GetPort(&oldport);	
	SetPort(win);

	GetDItem(win, diOffscreenHorizBuff, &itemtype, &itemhandle, &itemrect);
	NumToString(map->max_bufx, tmpstr);
	SetIText(itemhandle, tmpstr);

	GetDItem(win, diOffscreenVertiBuff, &itemtype, &itemhandle, &itemrect);
	NumToString(map->max_bufy, tmpstr);
	SetIText(itemhandle, tmpstr);
		
	ShowWindow(win);
	while (!done) {

		SetCursor(&QD(arrow));
		draw_default_button(win, diOffscreenOK);
		ModalDialog(NULL, &ditem);
		switch (ditem) {

			case diOffscreenOK:

				GetDItem(win, diOffscreenHorizBuff, &itemtype, &itemhandle, &itemrect);
	        			GetIText(itemhandle,tmpstr);
				StringToNum(tmpstr, itemnum);
				/* Dont allow negative values */
				map->max_bufx = max(*itemnum, 0);

				GetDItem(win, diOffscreenVertiBuff, &itemtype, &itemhandle, &itemrect);
	         			GetIText(itemhandle,tmpstr);
				StringToNum(tmpstr, itemnum);
				/* Dont allow negative values */
				map->max_bufy = max(*itemnum, 0);
				
				/* Redraw the gworld (and the map) */
				force_map_update(map);
				done = TRUE;
				break;

			case diOffscreenCancel:

				done = TRUE;
				break;

			default:
				break;
		}
	}
	DisposeDialog(win);
	SetPort(oldport);
	update_all_map_windows();
}

/* Dialog that sets the size of the meridian interval for a map. */

void
set_meridians(Map *map)
{
	short ditem, itemtype, done = FALSE;
	long *itemnum = 0;
	Handle itemhandle;  
	Rect itemrect;
	Str255 tmpstr;
	DialogPtr win;
	GrafPtr oldport;

	win = GetNewDialog(dMeridians, NULL, (DialogPtr) -1);
	GetPort(&oldport);	
	SetPort(win);

	GetDItem(win, diMeridiansOnOff, &itemtype, &itemhandle, &itemrect);
	SetCtlValue((ControlHandle) itemhandle, map->vp->draw_meridians);

	GetDItem(win, diMeridiansInterval, &itemtype, &itemhandle, &itemrect);
	NumToString(map->vp->meridian_interval, tmpstr);
	SetIText(itemhandle, tmpstr);

	ShowWindow(win);
	while (!done) {

		SetCursor(&QD(arrow));
		draw_default_button(win, diMeridiansOK);
		ModalDialog(NULL, &ditem);
		switch (ditem) {

			case diMeridiansOnOff:
				GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
				SetCtlValue((ControlHandle) itemhandle, !GetCtlValue((ControlHandle) itemhandle));
				break;

			case diMeridiansOK:
				GetDItem(win, diMeridiansOnOff, &itemtype, &itemhandle, &itemrect);
				map->vp->draw_meridians = GetCtlValue((ControlHandle) itemhandle);
				GetDItem(win, diMeridiansInterval, &itemtype, &itemhandle, &itemrect);
	        			GetIText(itemhandle,tmpstr);
				StringToNum(tmpstr, itemnum);
				/* Dont allow negative values */
				map->vp->meridian_interval = max(*itemnum, 0);

				/* Redraw the gworld (and the map) */
				force_map_update(map);
				done = TRUE;
				break;

			case diMeridiansCancel:

				done = TRUE;
				break;

			default:
				break;
		}
	}
	DisposeDialog(win);
	SetPort(oldport);
	update_all_map_windows();
}

/* The side renaming dialog includes places for all the different name-related
   properties of a side. */

static void
seed_side_rename_string(DialogPtr win, short ditem, char *str)
{
	Str255 tmpstr;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
	c2p((str ? str : ""), tmpstr);
	SetIText(itemhandle, tmpstr);
}

static char *
get_side_rename_string(DialogPtr win, short ditem)
{
	char *str;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
	str = get_string_from_item(itemhandle);
	if (empty_string(str))
	  str = NULL;
	return str;
}

void
side_rename_dialog(Side *side)
{
	short done = FALSE, changed = TRUE, ditem;
	char *str;
	DialogPtr win;

	win = GetNewDialog(dSideRename, NULL, (DialogPtr) -1L);
	while (!done) {
		if (changed) {
			/* Seed the items with the current side names. */
			seed_side_rename_string(win, diSideRenameName, side->name);
			seed_side_rename_string(win, diSideRenameFullName, side->longname);
			seed_side_rename_string(win, diSideRenameAcronym, side->shortname);
			seed_side_rename_string(win, diSideRenameNoun, side->noun);
			seed_side_rename_string(win, diSideRenamePluralNoun, side->pluralnoun);
			seed_side_rename_string(win, diSideRenameAdjective, side->adjective);
			seed_side_rename_string(win, diSideRenameEmblemName, side->emblemname);
			seed_side_rename_string(win, diSideRenameColorScheme, side->colorscheme);
			ShowWindow(win);
			changed = FALSE;
		}
		draw_default_button(win, diSideRenameOK);
		SetCursor(&QD(arrow));
		ModalDialog(NULL, &ditem);
		switch (ditem) {
			case diSideRenameOK:
				/* Actually change the side's slots. */
				net_set_side_name(dside, side, get_side_rename_string(win, diSideRenameName));
				net_set_side_longname(dside, side, get_side_rename_string(win, diSideRenameFullName));
				net_set_side_shortname(dside, side, get_side_rename_string(win, diSideRenameAcronym));
				net_set_side_noun(dside, side, get_side_rename_string(win, diSideRenameNoun));
				net_set_side_pluralnoun(dside, side, get_side_rename_string(win, diSideRenamePluralNoun));
				net_set_side_adjective(dside, side, get_side_rename_string(win, diSideRenameAdjective));
				net_set_side_emblemname(dside, side, get_side_rename_string(win, diSideRenameEmblemName));
				net_set_side_colorscheme(dside, side, get_side_rename_string(win, diSideRenameColorScheme));
				current_colorscheme[side_number(side)] = copy_string(side->colorscheme);
				dissect_colorscheme(side_number(side));
				init_emblem_images();
				ui_update_state();
				save_preferences();
				/* Tweak the side menu. */
				update_side_menu(dside);
				/* Force redisplay of everything that might use any side names. */
				force_overall_update();
				/* Fall into next case. */
			case diSideRenameCancel:
				done = TRUE;
				break;
			case diSideRenameRandom:
				net_set_side_name(dside, side, NULL);
				net_set_side_noun(dside, side, NULL);
				/* Always need to clear the plural noun cache before renaming... */
				net_set_side_pluralnoun(dside, side, NULL);
				net_set_side_adjective(dside, side, NULL);
				/* (should not be able to call this here!) */
				make_up_side_name(side);
				init_emblem_images();
				changed = TRUE;
				break;
		}
	}
	DisposeDialog(win);
	update_all_map_windows();
}


void
toggle_map_grid(Map *map)
{
	map->vp->draw_grid = !map->vp->draw_grid;
	/* (should not do a total redraw?) */
	force_map_update(map);
}

void
toggle_map_topline(Map *map)
{
	int oldtoph = map->toph;
	GrafPtr oldport;

	/* Setting the port fixed a display bug. */
	GetPort(&oldport);
	SetPort(map->window);
	map->draw_topline = !map->draw_topline;
	map->toplineh = (map->draw_topline ? tophgt : 0);
	/* Erase other-map boxes in other windows. */
	draw_related_maps(map);
	map->toph = map->toplineh + map->topunith;

#if 1

	/* This is a temp fix. It should be possible to get the code below to work! */
	force_map_update(map);

#else

	/* Update without scrolling if we are expanding and the buffer is too small. */ 
	if (map->bufy - map->offsety < oldtoph - map->toph) {
		set_content_rect(map);
		update_gworld(map);
		/* This is not done by update_gworld (unlike update_resized_gworld). */
		if (map->toplineh > 0)
		  draw_top_line(map);
		if (map->topunith > 0)
		  draw_unit_info(map);
	/* Always scroll the map if we are shrinking, or if the buffer is big enough. */
	} else update_resized_map(map);

#endif

	/* Redraw other-map boxes in other windows. */
	draw_related_maps(map);
	SetPort(oldport);
}

void
toggle_map_topunit(Map *map)
{
	GrafPtr oldport;
	int oldtoph;

	/* Setting the port fixed a display bug. */
	GetPort(&oldport);
	SetPort(map->window);
	oldtoph = map->toph;
	map->draw_topunit = !map->draw_topunit;
	map->topunith = (map->draw_topunit ? topunithgt : 0);
	/* Erase other-map boxes in other windows. */
	draw_related_maps(map);
	map->toph = map->toplineh + map->topunith;
	/* Update without scrolling if we are expanding and the buffer is too small. */ 
	if (map->bufy - map->offsety < oldtoph - map->toph) {
		set_content_rect(map);
		update_gworld(map);
		/* This is not done by update_gworld (unlike update_resized_gworld). */
		if (map->toplineh > 0)
		  draw_top_line(map);
		if (map->topunith > 0)
		  draw_unit_info(map);
	/* Always scroll the map if we are shrinking, or if the buffer is big enough. */
	} else update_resized_map(map);
	/* Redraw other-map boxes in other windows. */
	draw_related_maps(map);
	SetPort(oldport);
}

void
toggle_map_scrollbars(Map *map)
{
	/* Erase other-map boxes in other windows. */
	draw_related_maps(map);

	if (map->sbarwid)
		map->sbarwid = 0;
	else if (map == worldmap)
		map->sbarwid = floatsbarwid;
	else	map->sbarwid = sbarwid;
	
	adjust_map_decor(map);
	force_map_update(map);

	/* Redraw other-map boxes in other windows. */
	draw_related_maps(map);
}

void
toggle_map_cpanel(Map *map)
{
	/* Erase other-map boxes in other windows. */
	draw_related_maps(map);

	/* Toggle the panel. */
	map->conw = (map->conw > 0 ? 0 : conwid);
	adjust_map_decor(map);
	force_map_update(map);

	/* Redraw other-map boxes in other windows. */
	draw_related_maps(map);
}

void
toggle_map_other_maps(Map *map)
{
	map->vp->draw_other_maps = !map->vp->draw_other_maps;
	/* (should not do a total redraw) */
	force_map_update(map);
}

void
toggle_map_lighting(Map *map)
{
	map->vp->draw_lighting = !map->vp->draw_lighting;
	/* We have to do a total redraw. */
	force_map_update(map);
}

void
toggle_map_coverage(Map *map)
{
	map->vp->draw_cover = !map->vp->draw_cover;
	/* (should only change newly dimmed/lightened cells) */
	force_map_update(map);
}

void
toggle_map_names(Map *map)
{
	map->vp->draw_names = !map->vp->draw_names;
	/* (if now on, should draw names on top of everything, don't redraw everything) */
	if (map->vp->hh > 5) {
		force_map_update(map);
	} else {
		/* (should be a force update on control panel alone) */
		draw_control_panel(map);
	}
}

void
toggle_map_people(Map *map)
{
    if (!people_sides_defined())
      return;
	map->vp->draw_people = !map->vp->draw_people;
	if (bwid2[map->vp->power] > 0) {
		force_map_update(map);
	} else {
		/* (should be a force update on control panel alone) */
		draw_control_panel(map);
	}
}

void
toggle_map_control(Map *map)
{
    if (!control_sides_defined())
      return;
	map->vp->draw_control = !map->vp->draw_control;
	if (bwid2[map->vp->power] > 0) {
		force_map_update(map);
	} else {
		/* (should be a force update on control panel alone) */
		draw_control_panel(map);
	}
}

void
toggle_map_elevations(Map *map)
{
	map->vp->draw_elevations = !map->vp->draw_elevations;
	force_map_update(map);
}

void
toggle_map_materials(Map *map, int m)
{
	map->vp->draw_materials[m] = !map->vp->draw_materials[m];
	map->vp->num_materials_to_draw += (map->vp->draw_materials[m] ? 1 : -1);
	force_map_update(map);
}

void
toggle_map_aux_terrain(Map *map, int t)
{
	map->vp->draw_aux_terrain[t] = !map->vp->draw_aux_terrain[t];
	force_map_update(map);
}

void
toggle_map_temperature(Map *map)
{
	map->vp->draw_temperature = !map->vp->draw_temperature;
	force_map_update(map);
}

void
toggle_map_winds(Map *map)
{
	map->vp->draw_winds = !map->vp->draw_winds;
	force_map_update(map);
}

void
toggle_map_clouds(Map *map)
{
	map->vp->draw_clouds = !map->vp->draw_clouds;
	force_map_update(map);
}

void
toggle_map_storms(Map *map)
{
	map->vp->draw_storms = !map->vp->draw_storms;
	force_map_update(map);
}

void
toggle_map_plans(Map *map)
{
	map->vp->draw_plans = !map->vp->draw_plans;

	force_map_update(map);
}

void
toggle_map_ai(Map *map)
{
	if (!side_has_ai(dside))
	  return;
	map->vp->draw_ai = !map->vp->draw_ai;
	force_map_update(map);
}

void
toggle_map_sidecolors(Map *map)
{
	map->sidecolors = !map->sidecolors;
	force_map_update(map);
}

void
toggle_map_draw_emblems(Map *map)
{
	map->draw_emblems = !map->draw_emblems;
	force_map_update(map);
}

void
toggle_iconmasks(Map *map)
{
	map->iconmasks = !map->iconmasks;
	force_map_update(map);
}

void
toggle_boxmasks(Map *map)
{
	map->boxmasks = !map->boxmasks;
	force_map_update(map);
}

void
toggle_textmasks(Map *map)
{
	map->textmasks = !map->textmasks;
	force_map_update(map);
}

void
toggle_featureborders(Map *map)
{
	map->featureborders = !map->featureborders;
	force_map_update(map);
}

void
toggle_featurenames(Map *map)
{
	map->featurenames = !map->featurenames;
	force_map_update(map);
}

void
toggle_shorelines(Map *map)
{
	map->shorelines = !map->shorelines;
	force_map_update(map);
}

void
toggle_simple_borders(Map *map)
{
	map->simple_borders = !map->simple_borders;
	force_map_update(map);
}

void
toggle_optimize_fonts(Map *map)
{
	map->optimize_fonts = !map->optimize_fonts;
	force_map_update(map);
}

void
toggle_draw_meridians(Map *map)
{
	map->vp->draw_meridians = !map->vp->draw_meridians;
	force_map_update(map);
}

void
toggle_solid_color_terrain(Map *map)
{
	map->solid_color_terrain = !map->solid_color_terrain;
	force_map_update(map);
}

void
toggle_blinking_curunit(Map *map)
{
	map->blinking_curunit = !map->blinking_curunit;
	force_map_update(map);
}

void
toggle_selectionmasks(Map *map)
{
	map->selectionmasks = !map->selectionmasks;
	force_map_update(map);
}

void
toggle_erase_names(Map *map)
{
	map->erase_names = !map->erase_names;
	force_map_update(map);
}

