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

  1. /* Game designer handling for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING. */
  8.  
  9. #include "conq.h"
  10. #include "macconq.h"
  11.  
  12. #ifdef DESIGNERS
  13.  
  14. #define numtooltypes 12
  15.  
  16. extern MenuHandle featuremenu;
  17.  
  18. WindowPtr designwin = nil;
  19.  
  20. ControlHandle ttypepopup = nil;
  21. ControlHandle utypepopup = nil;
  22. ControlHandle mtypepopup = nil;
  23. ControlHandle sidepopup = nil;
  24. ControlHandle feature_add_button = nil;
  25. ControlHandle feature_remove_button = nil;
  26. ControlHandle feature_edit_button = nil;
  27. ControlHandle featurepopup = nil;
  28.  
  29. CursHandle paintcursors[numtooltypes];
  30. CursHandle bordpaintor;
  31. CursHandle connpaintor;
  32. CursHandle coatpaintor;
  33.  
  34. /* This is the width and height of each design tool's entry. */
  35.  
  36. int dtoolw = 120;
  37. int dtoolh = 36;
  38.  
  39. /* The type of designer tool currently in use. */
  40.  
  41. enum tooltype tooltype = notool;
  42.  
  43. /* All the state of the designer palette. */
  44.  
  45. short curbrushradius = 0;
  46. short curttype = 0;
  47. short curbgttype = 0;
  48. short curdepth = 1;
  49. short curutype = 0;
  50. short cursidenumber = 0;
  51. short curmtype = 0;
  52. short curmamount = 0;
  53. short curfid = 0;
  54. Feature *curfeature = NULL;
  55. short curelevation = 0;
  56. short curtemperature = 0;
  57. short curcloudtype = 0;
  58. short curcloudbottom = 0;
  59. short curcloudheight = 0;
  60. short curwinddir = 0;
  61. short curwindforce = 0;
  62. short curtview;
  63. short curuview;
  64.  
  65. /* These are globals used in drag painting. */
  66.  
  67. short painttype;
  68. short paintpeop;
  69. short paintfid;
  70. short painttview;
  71. short paintuview;
  72.  
  73. short enabledtooltype[20];
  74.  
  75. void
  76. enable_designing(int forsure)
  77. {
  78.     extern int compromised;
  79.  
  80.     if (dside == NULL || dside->designer)
  81.       return;
  82.     if (!forsure && !compromised) {
  83.         switch (CautionAlert(aConfirmDesign, nil)) {
  84.             case aiConfirmDesignOK:
  85.                 break;
  86.             case aiConfirmDesignCancel:
  87.                 return;
  88.         }
  89.     }
  90.     /* Actually change designer status, this will call back to alter all displays. */
  91.     become_designer(dside);
  92.     /* Create and add the designer's palette. */
  93.     if (designwin == nil) {
  94.         create_design_window();
  95.     }
  96.     if (designwin != nil) {
  97.         position_design_window();
  98.         ShowWindow(designwin);
  99. /*        SelectWindow(designwin); */
  100.     }
  101.     /* Recache visibility flags. */
  102.     calc_vision();
  103. }
  104.  
  105. void
  106. disable_designing()
  107. {
  108.     if (dside == NULL || !dside->designer)
  109.       return;
  110.     /* Hide (but don't destroy) the designer's palette. */
  111.     if (designwin != nil) {
  112.         HideWindow(designwin);
  113.     }
  114.     /* Actually change designer status, this will call back to alter all displays. */
  115.     become_nondesigner(dside);
  116.     /* Recache visibility flags. */
  117.     calc_vision();
  118. }
  119.  
  120. /* Each type of design tool has a distinct cursor. */
  121.  
  122. void
  123. init_design_cursors()
  124. {
  125.     paintcursors[terraintool] = GetCursor(cCell);
  126.     bordpaintor = GetCursor(cBord);
  127.     connpaintor = GetCursor(cConn);
  128.     coatpaintor = GetCursor(cCoat);
  129.     paintcursors[unittool] = GetCursor(cUnit);
  130.     paintcursors[peopletool] = GetCursor(cPeople);
  131.     paintcursors[materialtool] = GetCursor(cMaterial);
  132.     paintcursors[featuretool] = GetCursor(cFeature);
  133.     paintcursors[elevationtool] = GetCursor(cElevation);
  134.     paintcursors[temperaturetool] = GetCursor(cTemperature);
  135.     paintcursors[cloudstool] = GetCursor(cClouds);
  136.     paintcursors[windstool] = GetCursor(cWinds);
  137.     /* (should have a view-painting cursor) */
  138. }
  139.  
  140. /* Adjust the cursor to reflect the current designer tool. */
  141.  
  142. CursPtr
  143. adjust_designer_cursor(Point mouse, RgnHandle region)
  144. {
  145.     if (tooltype == terraintool && !t_is_cell(curttype)) {
  146.         switch (t_subtype(curttype)) {
  147.             case bordersubtype:
  148.                 return *bordpaintor;
  149.             case connectionsubtype:
  150.                 return *connpaintor;
  151.             case coatingsubtype:
  152.                 return *coatpaintor;
  153.             default:
  154.                 terrain_subtype_warning("cursor adjust", curttype);
  155.                 return &QD(arrow);
  156.         }
  157.     }
  158.     return *(paintcursors[tooltype]);
  159. }
  160.  
  161. /* Create the designer tool window. */
  162.  
  163. void
  164. create_design_window()
  165. {
  166.     if (hasColorQD) {
  167.         designwin = GetNewCWindow(wDesign, NULL, (WindowPtr) -1L);
  168.     } else {
  169.         designwin = GetNewWindow(wDesign, NULL, (WindowPtr) -1L);
  170.     }
  171.     add_window_menu_item("Design", designwin);  /* until this becomes a windoid */
  172.     /* Make the current side be the one with the display. */
  173.     cursidenumber = side_number(dside);
  174.     build_terrain_type_menu();
  175.     build_unit_type_menu();
  176.     build_side_menu();
  177.     build_material_type_menu();
  178.     build_feature_menu();
  179.     ttypepopup = GetNewControl(mTerrainTypes, designwin);
  180.     utypepopup = GetNewControl(mUnitTypes, designwin);
  181.     sidepopup = GetNewControl(mSides, designwin);
  182.     mtypepopup = GetNewControl(mMaterialTypes, designwin);
  183.     featurepopup = GetNewControl(mFeatures, designwin);
  184.     feature_add_button = GetNewControl(cFeatureAddButton, designwin);
  185.     feature_remove_button = GetNewControl(cFeatureRemoveButton, designwin);
  186.     feature_edit_button = GetNewControl(cFeatureEditButton, designwin);
  187.     SizeWindow(designwin, 2 * dtoolw - 1, (numtooltypes / 2) * dtoolh - 1, 1);
  188.     position_design_window();
  189.     init_design_cursors();
  190.     enabledtooltype[notool] = TRUE;
  191.     enabledtooltype[terraintool] = TRUE;
  192.     enabledtooltype[unittool] = TRUE;
  193.     enabledtooltype[peopletool] = TRUE;
  194.     enabledtooltype[featuretool] = TRUE;
  195.     enabledtooltype[brushsizetool] = TRUE;
  196.     enabledtooltype[materialtool] = any_materials_in_terrain;
  197.     enabledtooltype[elevationtool] = !world_is_flat();
  198.     enabledtooltype[temperaturetool] = any_temp_variation;
  199.     enabledtooltype[cloudstool] = any_clouds;
  200.     enabledtooltype[windstool] = any_wind_variation;
  201.     enabledtooltype[viewtool] = !g_see_all();
  202.     ShowWindow(designwin);
  203. }
  204.  
  205. /* Try to put the palette alongside the frontmost window. */
  206.  
  207. void
  208. position_design_window()
  209. {
  210.     Point pt;
  211.     WindowPtr win;
  212.     GrafPtr oldport;
  213.  
  214.     /* (should fix all this) */
  215.     if ((win = FrontWindow()) != nil) {
  216.         GetPort(&oldport);
  217.         SetPort(win);
  218.         SetPt(&pt, win->portRect.right + 3, win->portRect.top);
  219.         LocalToGlobal(&pt);
  220.         SetPort(oldport);
  221.     } else {
  222.         SetPt(&pt, 500, 50);
  223.     }
  224.     /* (should make sure is not off the edge of the screen) */
  225.     if (pt.h + 2 * dtoolw > 640 /* is off screen entirely */) {
  226.         SetPt(&pt, 640 - 2 * dtoolw - 2, 50);
  227.     }
  228.     MoveWindow(designwin, pt.h, pt.v, TRUE);
  229. }
  230.  
  231. void
  232. draw_design_window()
  233. {
  234.     int i;
  235.     GrafPtr oldport;
  236.  
  237.     if (!active_display(dside) || designwin == nil) return;
  238.     GetPort(&oldport);
  239.     SetPort(designwin);
  240.     /* Draw each tool's palette item. */
  241.     for (i = 0; i < numtooltypes; ++i) {
  242.         draw_design_window_tool(i);
  243.     }
  244.     DrawControls(designwin);
  245.     SetPort(oldport);
  246. }
  247.  
  248. void
  249. draw_design_window_tool(enum tooltype tool)
  250. {
  251.     int enabled = TRUE, paintable = TRUE;
  252.     char *toolname = NULL, *auxtoolname = NULL;
  253.     Rect tmprect, imagerect;
  254.     char imbuf[BUFSIZE];
  255.     Str255 tmpstr;
  256.  
  257.     SetRect(&tmprect, 0, 0, dtoolw, dtoolh);
  258.     OffsetRect(&tmprect, (tool / (numtooltypes/2)) * dtoolw, (tool % (numtooltypes/2)) * dtoolh);
  259.     EraseRect(&tmprect);
  260.     /* Confine the image to a square subrect on the left side of the window. */
  261.     imagerect = tmprect;
  262.     imagerect.right = imagerect.left + dtoolh;
  263.     imbuf[0] = '\0';
  264.     switch (tool) {
  265.         case notool:
  266.             toolname = "Normal";
  267.             break;
  268.         case terraintool:
  269.             toolname = t_type_name(curttype);
  270.             InsetRect(&imagerect, (dtoolh - hws[4]) / 2, (dtoolh - hhs[4]) / 2);
  271.             /* Only do bg terrain type if painting cell terrain. */
  272.             if (t_is_cell(curttype)) {
  273.                 auxtoolname = t_type_name(curbgttype);
  274.                 /* bg type is always cell subtype. */
  275.                 OffsetRect(&imagerect, 3, 3);
  276.                 draw_terrain_sample(imagerect, curbgttype);
  277.                 OffsetRect(&imagerect, -6, -6);
  278.             }
  279.             draw_terrain_sample(imagerect, curttype);
  280.             break;
  281.         case unittool:
  282.             toolname = u_type_name(curutype);
  283.             InsetRect(&imagerect, (dtoolh - 32) / 2, (dtoolh - 32) / 2);
  284.              draw_unit_image(designwin, imagerect.left, imagerect.top, 32, 32,
  285.                              curutype, cursidenumber, 0);
  286.             /* Gray out the unit if not allowed for the current side. */
  287.             paintable = type_allowed_on_side(curutype, side_n(cursidenumber));
  288.             break;
  289.         case peopletool:
  290.             toolname = shortest_side_title(side_n(cursidenumber), spbuf);
  291.             InsetRect(&imagerect, (dtoolh - 16) / 2, (dtoolh - 16) / 2);
  292.             draw_side_emblem(designwin, imagerect.left, imagerect.top, 16, 16,
  293.                              cursidenumber, shadow_emblem);
  294.             break;
  295.         case featuretool:
  296.             if (enabledtooltype[featuretool]) {
  297.                 if (curfeature == NULL) {
  298.                     curfeature = find_feature(curfid);
  299.                 }
  300.                 if (curfeature != NULL) {
  301.                     toolname = curfeature->name;
  302.                     auxtoolname = curfeature->typename;
  303.                 }
  304.             } else {
  305.                 toolname = "Feature";
  306.                 enabled = FALSE;
  307.             }
  308.             break;
  309.         case brushsizetool:
  310.             OffsetRect(&imagerect, dtoolh/2 - curbrushradius, dtoolh/2 - curbrushradius);
  311.             imagerect.right = imagerect.left + curbrushradius + 1;
  312.             imagerect.bottom = imagerect.top + curbrushradius + 1;
  313.             FillOval(&imagerect, QDPat(black));
  314.             if (curbrushradius > 0) {
  315.                 sprintf(imbuf, "%d", curbrushradius);
  316.             }
  317.             toolname = "Brush";
  318.             break;
  319.         case materialtool:
  320.             if (enabledtooltype[materialtool]) {
  321.                 toolname = m_type_name(curmtype);
  322.                 sprintf(imbuf, "%d", curmamount);
  323.             } else {
  324.                 toolname = "Material";
  325.                 enabled = FALSE;
  326.             }
  327.             break;
  328.         case elevationtool:
  329.             if (enabledtooltype[elevationtool]) {
  330.                 sprintf(spbuf, "Elev %d", curelevation);
  331.                 toolname = spbuf;
  332.             } else {
  333.                 toolname = "Elevation";
  334.                 enabled = FALSE;
  335.             }
  336.             break;
  337.         case temperaturetool:
  338.             if (enabledtooltype[temperaturetool]) {
  339.                 sprintf(spbuf, "Temp %d°", curtemperature);
  340.                 toolname = spbuf;
  341.             } else {
  342.                 toolname = "Temperature";
  343.                 enabled = FALSE;
  344.             }
  345.             break;
  346.         case cloudstool:
  347.             if (enabledtooltype[cloudstool]) {
  348.                 /* Black is not ideal here... */
  349.                 FillRect(&imagerect, QDPat(black));
  350.                 if (curcloudtype > 0) {
  351.                     InsetRect(&imagerect, (dtoolh - hws[4]) / 2, (dtoolh - hhs[4]) / 2);
  352.                     draw_clouds(imagerect.left, imagerect.top, 4, curcloudtype);
  353.                     sprintf(spbuf, "Cloudy (%d)", curcloudtype);
  354.                     toolname = spbuf;
  355.                 } else {
  356.                     toolname = "Clear";
  357.                 }
  358.             } else {
  359.                 toolname = "Clouds";
  360.                 enabled = FALSE;
  361.             }
  362.             break;
  363.         case windstool:
  364.             if (enabledtooltype[windstool]) {
  365.                 InsetRect(&imagerect, (dtoolh - hws[4]) / 2, (dtoolh - hhs[4]) / 2);
  366.                 draw_winds(imagerect.left, imagerect.top, 4, curwinddir, curwindforce);
  367.                 if (curwindforce > 0) {
  368.                     sprintf(spbuf, "Winds %s, %d", dirnames[curwinddir], curwindforce);
  369.                     toolname = spbuf;
  370.                 } else {
  371.                     toolname = "Calm";
  372.                 }
  373.             } else {
  374.                 toolname = "Winds";
  375.                 enabled = FALSE;
  376.             }
  377.             break;
  378.         case viewtool:
  379.             if (enabledtooltype[viewtool]) {
  380.                 toolname = "View";
  381.             } else {
  382.                 toolname = "View";
  383.                 enabled = FALSE;
  384.             }
  385.             break;
  386.         default:
  387.             /* ??? */
  388.             break;
  389.     }
  390.     TextSize(12);
  391.     /* Draw a (short) text string in the image area. */
  392.     if (strlen(imbuf) > 0) {
  393.         /* (should center) */
  394.         MoveTo(tmprect.left + (dtoolh - StringWidth(tmpstr)) / 2, tmprect.bottom - 5);
  395.         DrawText(imbuf, 0, strlen(imbuf));
  396.     }
  397.     if (toolname != NULL) {
  398.         MoveTo(tmprect.left + dtoolh, tmprect.top + (auxtoolname != NULL ? dtoolh / 4 + 4
  399.                                                            : dtoolh / 2 + 5));
  400.         if (tool == featuretool)
  401.           Move(- dtoolh, 0);
  402.         DrawText(toolname, 0, strlen(toolname));
  403.     }
  404.     if (auxtoolname != NULL) {
  405.         MoveTo(tmprect.left + dtoolh, tmprect.top + (dtoolh * 3) / 4);
  406.         if (tool == featuretool)
  407.           Move(- dtoolh, 0);
  408.         DrawText(auxtoolname, 0, strlen(auxtoolname));
  409.     }
  410.     if (!paintable) {
  411.         gray_out_rect(&tmprect);
  412.     }
  413.     if (!enabled) {
  414.         gray_out_rect(&tmprect);
  415.     }
  416.     /* Draw gray dividing lines. */
  417.     PenPat(QDPat(gray));
  418.     MoveTo(tmprect.right - 1, tmprect.top);  Line(0, dtoolh);
  419.     MoveTo(tmprect.left, tmprect.bottom - 1);  Line(dtoolw, 0);
  420.     PenNormal();
  421.     /* Highlight the currently selected tool with a heavy outline rect. */
  422.     if (tool == tooltype) {
  423.         tmprect.bottom -= 1;  tmprect.right -= 1;
  424.         InvertRect(&tmprect);
  425.         InsetRect(&tmprect, 3, 3);
  426.         InvertRect(&tmprect);
  427.         if (!enabledtooltype[tool]) {
  428.             InsetRect(&tmprect, -3, -3);
  429.             gray_out_rect(&tmprect);
  430.         }
  431.     }
  432. }
  433.  
  434. /* Respond to a mouse down in the designer's window. */
  435.  
  436. /* This macro implements cycling of a variable through a set of consecutive
  437.    values, with direction controlled by the shift key.  If the limit is 0,
  438.    then the cycling part is not done. */
  439.  
  440. #define OPTION_CYCLE(var, lo, hi, mods)  \
  441.   if ((hi) - (lo) > 0) {  \
  442.     (var) = (((var) + ((mods) & shiftKey ? -1 : 1) - (lo) + ((hi) - (lo))) % ((hi) - (lo))) + (lo);  \
  443.   } else {  \
  444.     (var) = ((var) + ((mods) & shiftKey ? -1 : 1));  \
  445.   }
  446.  
  447. void
  448. do_mouse_down_design(Point mouse, int mods)
  449. {
  450.     int oldtool, poppedtool, newutype, newbgttype, toolchoice;
  451.     Feature *feature;
  452.     Rect tmprect;
  453.     ControlHandle control;
  454.     long choice;
  455.     extern int nextfid;
  456.  
  457.     tmprect.left = 0;  tmprect.right = dtoolw;
  458.     oldtool = poppedtool = tooltype;
  459.     toolchoice = (mouse.v / dtoolh) + (mouse.h > dtoolw ? (numtooltypes / 2) : 0);
  460.     FindControl(mouse, designwin, &control);
  461.     if (control == ttypepopup) {
  462.         TrackControl(control, mouse, (void *) -1);
  463.         choice = LoWord(GetCtlValue(control));
  464.         if (choice > 0) curttype = choice - 1;
  465.         poppedtool = terraintool;
  466.     } else if (control == utypepopup) {
  467.         mark_allowed_unit_types();
  468.         TrackControl(control, mouse, (void *) -1);
  469.         choice = LoWord(GetCtlValue(control));
  470.         if (choice > 0) curutype = choice - 1;
  471.         poppedtool = unittool;
  472.     } else if (control == sidepopup) {
  473.         mark_allowed_sides();
  474.         TrackControl(control, mouse, (void *) -1);
  475.         choice = LoWord(GetCtlValue(control));
  476.         if (choice > 0) {
  477.             cursidenumber = choice;
  478.             if (cursidenumber > numsides) cursidenumber = 0;;
  479.         }
  480.         poppedtool = peopletool;
  481.     } else if (control == mtypepopup) {
  482.         TrackControl(control, mouse, (void *) -1);
  483.         choice = LoWord(GetCtlValue(control));
  484.         if (choice > 0) curmtype = choice - 1;
  485.         poppedtool = materialtool;
  486.     } else if (control == featurepopup) {
  487.         TrackControl(control, mouse, (void *) -1);
  488.         choice = LoWord(GetCtlValue(control));
  489.         if (choice > 0) {
  490.             curfid = choice - 1; /* not reliable */
  491.             curfeature = find_feature(curfid);
  492.         }
  493.         poppedtool = featuretool;
  494.     } else if (control == feature_add_button) {
  495.         sprintf(spbuf, "%d", nextfid);
  496.         feature = create_feature("feature", copy_string(spbuf));
  497.         if (feature != NULL) {
  498.             curfeature = feature;
  499.             curfid = feature->id;
  500.             feature_rename_dialog(feature);
  501.             update_feature_menu(feature);
  502.         }
  503.         poppedtool = featuretool;
  504.     } else if (control == feature_remove_button) {
  505.         destroy_feature(curfeature);
  506.         curfeature = NULL;
  507.         curfid = 0;
  508.         build_feature_menu();
  509.     } else if (control == feature_edit_button) {
  510.         feature_rename_dialog(curfeature);
  511.         poppedtool = featuretool;
  512.     } else if (enabledtooltype[toolchoice]) {
  513.         /* Any other click selects the tool. */
  514.         if (toolchoice != brushsizetool) tooltype = toolchoice;
  515.         /* Now handle any shortcuts. */
  516.         switch (toolchoice) {
  517.             case notool:
  518.                 break;
  519.             case terraintool:
  520.                 if (mods & optionKey) {
  521.                     /* Option-click and Option-Shift-click cycle through all
  522.                        the "foreground" terrain types. */
  523.                     OPTION_CYCLE(curttype, 0, numttypes, mods);
  524.                 } else if ((mods & cmdKey) && t_is_cell(curttype)) {
  525.                     /* Cmd-click and Cmd-Shift-click cycle through all
  526.                        the "background" terrain types. */
  527.                     newbgttype = curbgttype;
  528.                     do {
  529.                         OPTION_CYCLE(newbgttype, 0, numttypes, mods);
  530.                         if (newbgttype == curbgttype)
  531.                           break;
  532.                     } while (!t_is_cell(newbgttype));
  533.                     curbgttype = newbgttype;
  534.                 }
  535.                 break;
  536.             case unittool:
  537.                 if (mods & optionKey) {
  538.                     /* Option-click and Option-Shift-click cycle through all
  539.                        the types allowed for the current side. */
  540.                     newutype = curutype;
  541.                     do {
  542.                         OPTION_CYCLE(newutype, 0, numutypes, mods);
  543.                         if (newutype == curutype) break;
  544.                     } while (!type_allowed_on_side(newutype, side_n(cursidenumber)));
  545.                     curutype = newutype;
  546.                 }
  547.                 break;
  548.             case peopletool:
  549.                 if (mods & optionKey) {
  550.                     /* Option-click and Option-Shift-click cycle around all the sides. */
  551.                     OPTION_CYCLE(cursidenumber, 0, numsides + 1, mods);
  552.                 }
  553.                 break;
  554.             case featuretool:
  555.                 if (mods & optionKey && nextfid > 1) {
  556.                     /* Option-click and Option-Shift-click cycle around the features. */
  557.                     OPTION_CYCLE(curfid, 0, nextfid, mods);
  558.                     curfeature = find_feature(curfid);
  559.                 }
  560.                 break;
  561.             case brushsizetool:
  562.                 if (mods & optionKey) {
  563.                     /* Option-click and Option-Shift-click cycle through brush sizes. */
  564.                     OPTION_CYCLE(curbrushradius, 0, 99, mods);
  565.                 }
  566.                 break;
  567.             case materialtool:
  568.                 if (mods & optionKey) {
  569.                     /* Option-click and Option-Shift-click cycle around amounts. */
  570.                     OPTION_CYCLE(curmamount, 0, 99, mods);
  571.                 }
  572.                 break;
  573.             case elevationtool:
  574.                 if (mods & optionKey) {
  575.                     /* Option-click and Option-Shift-click adjust the elevation. */
  576.                     OPTION_CYCLE(curelevation, minelev, maxelev + 1, mods);
  577.                 }
  578.                 break;
  579.             case temperaturetool:
  580.                 if (mods & optionKey) {
  581.                     /* Option-click and Option-Shift-click adjust the temp. */
  582.                     OPTION_CYCLE(curtemperature, mintemp, maxtemp + 1, mods);
  583.                 }
  584.                 break;
  585.             case cloudstool:
  586.                 if (mods & optionKey) {
  587.                     /* Option-click and Option-Shift-click adjust the cloud type. */
  588.                     OPTION_CYCLE(curcloudtype, 0, 4, mods);
  589.                 }
  590.                 break;
  591.             case windstool:
  592.                 if (mods & optionKey) {
  593.                     /* Option-click and Option-Shift-click adjust the wind force. */
  594.                     OPTION_CYCLE(curwindforce, minwindforce, maxwindforce, mods);
  595.                 } else if (mods & cmdKey) {
  596.                     /* Cmd-click and Cmd-Shift-click adjust the direction. */
  597.                     OPTION_CYCLE(curwinddir, 0, NUMDIRS, mods);
  598.                 }
  599.                 break;
  600.             case viewtool:
  601.                 /* Nothing to do? */
  602.                 break;
  603.             default:
  604.                 break;
  605.         }
  606.     }
  607.     /* Draw the old and new tools. */
  608.     if (oldtool != tooltype) {
  609.         draw_design_window_tool(oldtool);
  610.     }
  611.     if (poppedtool != tooltype) {
  612.         draw_design_window_tool(poppedtool);
  613.     }
  614.     draw_design_window_tool(tooltype);
  615.     if (toolchoice != tooltype) draw_design_window_tool(toolchoice);
  616.     /* As a special case, redraw the unit tool if the side tool was touched. */
  617.     if (tooltype == peopletool || poppedtool == peopletool) {
  618.         draw_design_window_tool(unittool);
  619.     }
  620.     /* (should only draw controls in relevant tools) */
  621.     DrawControls(designwin);
  622. }
  623.  
  624. void
  625. mark_allowed_unit_types()
  626. {
  627.     Side *side = side_n(cursidenumber);
  628.     int u;
  629.  
  630.     for_all_unit_types(u) {
  631.         EnableItem(utypemenu, u + 1);
  632.         SetItemMark(utypemenu, u + 1,
  633.                     (type_allowed_on_side(u, side) ? diamondMark : noMark));
  634.     }
  635. }
  636.  
  637. void
  638. mark_allowed_sides()
  639. {
  640.     Side *side;
  641.  
  642.     for_all_sides(side) {
  643.         EnableItem(sidemenu, side_number(side));
  644.         SetItemMark(sidemenu, side_number(side),
  645.                     (type_allowed_on_side(curutype, side) ? diamondMark : noMark));
  646.     }
  647.     EnableItem(sidemenu, numsides + 1);
  648.     SetItemMark(sidemenu, numsides + 1,
  649.                 (type_allowed_on_side(curutype, NULL) ? diamondMark : noMark));
  650. }
  651.  
  652. void
  653. feature_rename_dialog(Feature *feature)
  654. {
  655.     short done = FALSE, ditem;
  656.     char *newtypename, *newname;
  657.     Str255 tmpstr;
  658.     DialogPtr win;
  659.     short itemtype;  Handle itemhandle;  Rect itemrect;
  660.  
  661.     if (feature == NULL) return;
  662.     win = GetNewDialog(dFeatureRename, NULL, (DialogPtr) -1L);
  663.     /* Seed the text items with the original names. */
  664.     newtypename = feature->typename;
  665.     if (newtypename == NULL) newtypename = "";
  666.     GetDItem(win, diFeatureRenameType, &itemtype, &itemhandle, &itemrect);
  667.     c2p(newtypename, tmpstr);
  668.     SetIText(itemhandle, tmpstr);
  669.     newname = feature->name;
  670.     if (newname == NULL) newname = "";
  671.     GetDItem(win, diFeatureRenameName, &itemtype, &itemhandle, &itemrect);
  672.     c2p(newname, tmpstr);
  673.     SetIText(itemhandle, tmpstr);
  674.     ShowWindow(win);
  675.     while (!done) {
  676.         /* Deactivate the front window. */
  677.         activate_window(FrontWindow(), FALSE);
  678.         SetCursor(&QD(arrow));
  679.         ModalDialog(NULL, &ditem);
  680.         switch (ditem) {
  681.             case diRenameOK:
  682.                 GetDItem(win, diFeatureRenameType, &itemtype, &itemhandle, &itemrect);
  683.                 set_feature_type_name(feature, get_string_from_item(itemhandle));
  684.                 GetDItem(win, diFeatureRenameName, &itemtype, &itemhandle, &itemrect);
  685.                 set_feature_name(feature, get_string_from_item(itemhandle));
  686.                 /* Fall into next case. */
  687.             case diRenameCancel:
  688.                 done = TRUE;
  689.                 break;
  690.         }
  691.     }
  692.     DisposDialog(win);
  693. }
  694.  
  695. /* Handling of mousedowns in the map when designing. */
  696.  
  697. void
  698. apply_designer_tool(Map *map, int h, int v, int mods)
  699. {
  700.     int x, y, dir;
  701.     int oldt, oldpeop, oldfid, oldtview, olduview;
  702.     Unit *unit;
  703.  
  704.     m_nearest_boundary(map, h, v, &x, &y, &dir);
  705.     switch (tooltype) {
  706.         case terraintool:
  707.             /* Dispatch on terrain subtype. */
  708.             switch (t_subtype(curttype)) {
  709.                 case cellsubtype:
  710.                     /* Choose to paint fg or bg type, depending on what's already
  711.                        there. */
  712.                     oldt = terrain_at(x, y);
  713.                     painttype = (curttype == oldt ? curbgttype : curttype);
  714.                     paint_cell(dside, x, y, curbrushradius, painttype);
  715.                     paint_on_drag(map, h, v, mods);
  716.                     break;
  717.                 case bordersubtype:
  718.                     /* Toggle border on first mouse down. */
  719.                     paint_border(dside, x, y, dir, curttype, -1);
  720.                     /* Dragging then adds or removes, depending on toggle's result. */
  721.                     border_on_drag(map, h, v, mods, border_at(x, y, dir, curttype));
  722.                     break;
  723.                 case connectionsubtype:
  724.                     /* Toggle connection on first mouse down. */
  725.                     paint_connection(dside, x, y, dir, curttype, -1);
  726.                     /* Dragging then adds or removes, depending on toggle's result. */
  727.                     connect_on_drag(map, h, v, mods, connection_at(x, y, dir, curttype));
  728.                     break;
  729.                 case coatingsubtype:
  730.                     paint_coating(dside, x, y, curbrushradius, curttype, curdepth);
  731.                     paint_on_drag(map, h, v, mods);
  732.                     break;
  733.                 default:
  734.                     terrain_subtype_warning("apply tool", curttype);
  735.                     break;
  736.             }
  737.             return;
  738.         case unittool:
  739.             /* A last check, should never(?) fail. */
  740.             if (!type_allowed_on_side(curutype, side_n(cursidenumber))) {
  741.                 beep();
  742.                 return;
  743.             }
  744.             unit = designer_create_unit(dside, curutype, cursidenumber, x, y);
  745.             if (unit != NULL) {
  746.                 /* Make the new unit automatically be the current selection. */
  747.                 unselect_all(map);
  748.                 select_unit_on_map(map, unit);
  749.                 draw_selections_at(map, unit->x, unit->y);
  750.             } else {
  751.                 /* Beep if the creation failed for some reason. */
  752.                 beep();
  753.             }
  754.             /* No use for drag painting here, unlike most other tools. */
  755.             break;
  756.         case peopletool:
  757.             /* Paint people or clear, inverting from what is already here. */
  758.             oldpeop = people_side_at(x, y);
  759.             paintpeop = (cursidenumber == oldpeop ? NOBODY : cursidenumber);
  760.             paint_people(dside, x, y, curbrushradius, paintpeop);
  761.             paint_on_drag(map, h, v, mods);
  762.             break;
  763.         case featuretool:
  764.             oldfid = raw_feature_at(x, y);
  765.             paintfid = (curfid == oldfid ? 0 : curfid);
  766.             paint_feature(dside, x, y, curbrushradius, paintfid);
  767.             paint_on_drag(map, h, v, mods);
  768.             break;
  769.         case materialtool:
  770.             paint_material(dside, x, y, curbrushradius, curmtype, curmamount);
  771.             paint_on_drag(map, h, v, mods);
  772.             break;
  773.         case elevationtool:
  774.             paint_elevation(dside, x, y, curbrushradius, curelevation);
  775.             paint_on_drag(map, h, v, mods);
  776.             break;
  777.         case temperaturetool:
  778.             paint_temperature(dside, x, y, curbrushradius, curtemperature);
  779.             paint_on_drag(map, h, v, mods);
  780.             break;
  781.         case cloudstool:
  782.             paint_clouds(dside, x, y, curbrushradius, curcloudtype, curcloudbottom, curcloudheight);
  783.             paint_on_drag(map, h, v, mods);
  784.             break;
  785.         case windstool:
  786.             paint_winds(dside, x, y, curbrushradius, curwinddir, curwindforce);
  787.             paint_on_drag(map, h, v, mods);
  788.             break;
  789.         case viewtool:
  790.             if (dside->terrview == NULL || dside->unitview == NULL)
  791.               break;
  792.             oldtview = terrain_view(dside, x, y);
  793.             painttview = (curtview == oldtview ? UNSEEN : curtview);
  794.             olduview = unit_view(dside, x, y);
  795.             paintuview = (curuview == olduview ? EMPTY : curuview);
  796.             paint_view(dside, x, y, curbrushradius, painttview, paintuview);
  797.             paint_on_drag(map, h, v, mods);
  798.             break;
  799.         default:
  800.             beep();
  801.     }
  802. }
  803.  
  804. void
  805. paint_on_drag(Map *map, int h0, int v0, int mods)
  806. {
  807.     Point pt0, pt1, newmouse;
  808.     int drawn = FALSE, x, y;
  809.     Rect tmprect;
  810.  
  811.     SetPt(&pt0, h0, v0);
  812.     SetPt(&pt1, h0, v0);
  813.     SetRect(&tmprect, h0, v0, h0, v0);
  814.     while (WaitMouseUp()) {
  815.         GetMouse(&newmouse);
  816.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  817.             pt1 = newmouse;
  818.             if (m_nearest_cell(map, pt1.h, pt1.v, &x, &y)) {
  819.                 switch (tooltype) {
  820.                     case terraintool:
  821.                         /* Dispatch on terrain subtype. */
  822.                         switch (t_subtype(curttype)) {
  823.                             /* This sort of drag-paint only works for area fillers,
  824.                                bords/conns use different algorithm. */
  825.                             case cellsubtype:
  826.                                 paint_cell(dside, x, y, curbrushradius, painttype);
  827.                                 break;
  828.                             case coatingsubtype:
  829.                                 paint_coating(dside, x, y, curbrushradius, curttype, curdepth);
  830.                                 break;
  831.                         }
  832.                         break;
  833.                     case peopletool:
  834.                         paint_people(dside, x, y, curbrushradius, paintpeop);
  835.                         break;
  836.                     case materialtool:
  837.                         paint_material(dside, x, y, curbrushradius, curmtype, curmamount);
  838.                         break;
  839.                     case featuretool:
  840.                         paint_feature(dside, x, y, curbrushradius, paintfid);
  841.                         break;
  842.                     case elevationtool:
  843.                         paint_elevation(dside, x, y, curbrushradius, curelevation);
  844.                         break;
  845.                     case temperaturetool:
  846.                         paint_temperature(dside, x, y, curbrushradius, curtemperature);
  847.                         break;
  848.                     case cloudstool:
  849.                         paint_clouds(dside, x, y, curbrushradius, curcloudtype, curcloudbottom, curcloudheight);
  850.                         break;
  851.                     case windstool:
  852.                         paint_winds(dside, x, y, curbrushradius, curwinddir, curwindforce);
  853.                         break;
  854.                     case viewtool:
  855.                         paint_view(dside, x, y, curbrushradius, curtview, curuview);
  856.                         break;
  857.                     default:
  858.                         break;
  859.                 }
  860.             }
  861.         }
  862.     }
  863. }
  864.  
  865. void
  866. border_on_drag(Map *map, int h0, int v0, int mods, int paintmode)
  867. {
  868.     Point pt0, pt1, newmouse;
  869.     int drawn = FALSE, x, y, dir;
  870.     Rect tmprect;
  871.  
  872.     SetPt(&pt0, h0, v0);
  873.     SetPt(&pt1, h0, v0);
  874.     SetRect(&tmprect, h0, v0, h0, v0);
  875.     while (WaitMouseUp()) {
  876.         GetMouse(&newmouse);
  877.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  878.             pt1 = newmouse;
  879.             m_nearest_boundary(map, pt1.h, pt1.v, &x, &y, &dir);
  880.             if (inside_area(x, y)) {
  881.                 paint_border(dside, x, y, dir, curttype, paintmode);
  882.             }
  883.         }
  884.     }
  885. }
  886.  
  887. void
  888. connect_on_drag(Map *map, int h0, int v0, int mods, int paintmode)
  889. {
  890.     Point pt0, pt1, newmouse;
  891.     int drawn = FALSE, x, y, dir;
  892.     Rect tmprect;
  893.  
  894.     SetPt(&pt0, h0, v0);
  895.     SetPt(&pt1, h0, v0);
  896.     SetRect(&tmprect, h0, v0, h0, v0);
  897.     while (WaitMouseUp()) {
  898.         GetMouse(&newmouse);
  899.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  900.             pt1 = newmouse;
  901.             m_nearest_boundary(map, pt1.h, pt1.v, &x, &y, &dir);
  902.             if (inside_area(x, y)) {
  903.                 paint_connection(dside, x, y, dir, curttype, paintmode);
  904.             }
  905.         }
  906.     }
  907. }
  908.  
  909. /* This allows the designer to choose which parts of a game to write out. */
  910.  
  911. int defunitids; /* should be module slot */
  912.  
  913. void
  914. designer_save_dialog()
  915. {
  916.     int done = FALSE;
  917.     short ditem;
  918.     char namebuf[BUFSIZE];
  919.     Str255 tmpstr;
  920.     Point pnt;
  921.     WindowPtr win;
  922.     Module *module;
  923.     SFReply reply;
  924.     short itemtype;  Handle itemhandle;  Rect itemrect;
  925.     
  926.     win = GetNewDialog(dDesignerSave, NULL, (DialogPtr) -1L);
  927.     module = create_game_module(NULL);
  928.     module->title = "Designer-saved data";
  929.     if (module == NULL) {
  930.         beep();
  931.         return;
  932.     }
  933.     init_module_reshape(module);
  934.     /* Only rarely does the designer not want to compress all the area layers. */
  935.     module->compresslayers = TRUE;
  936.     GetDItem(win, diDesignerSaveCompress, &itemtype, &itemhandle, &itemrect);
  937.     SetCtlValue((ControlHandle) itemhandle, module->compresslayers);
  938.     while (!done) {
  939.         /* Deactivate the front window. */
  940.         activate_window(FrontWindow(), FALSE);
  941.         SetCursor(&QD(arrow));
  942.         ModalDialog(NULL, &ditem);
  943.         switch (ditem) {
  944.             case diDesignerSaveOK:
  945.                 get_string_from_ditem(diDesignerSaveName, namebuf);
  946.                 module->name = copy_string(namebuf);
  947.                 set_flag_from_ditem(diDesignerSaveTypes, module->deftypes);
  948.                 set_flag_from_ditem(diDesignerSaveTables, module->deftables);
  949.                 set_flag_from_ditem(diDesignerSaveGlobals, module->defglobals);
  950.                 set_flag_from_ditem(diDesignerSaveWorld, module->defworld);
  951.                 set_flag_from_ditem(diDesignerSaveAreas, module->defareas);
  952.                 set_flag_from_ditem(diDesignerSaveAreaTerrain, module->defareaterrain);
  953.                 set_flag_from_ditem(diDesignerSaveAreaMisc, module->defareamisc);
  954.                 set_flag_from_ditem(diDesignerSaveAreaWeather, module->defareaweather);
  955.                 set_flag_from_ditem(diDesignerSaveAreaMaterial, module->defareamaterial);
  956.                 set_flag_from_ditem(diDesignerSaveSides, module->defsides);
  957.                 set_flag_from_ditem(diDesignerSaveSideViews, module->defsideviews);
  958.                 set_flag_from_ditem(diDesignerSavePlayers, module->defplayers);
  959.                 set_flag_from_ditem(diDesignerSaveUnits, module->defunits);
  960.                 set_flag_from_ditem(diDesignerSaveUnitIds, defunitids);
  961.                 set_flag_from_ditem(diDesignerSaveUnitProps, module->defunitprops);
  962.                 set_flag_from_ditem(diDesignerSaveUnitMoves, module->defunitacts);
  963.                 set_flag_from_ditem(diDesignerSaveUnitPlans, module->defunitplans);
  964.                 set_flag_from_ditem(diDesignerSaveScoring, module->defscoring);
  965.                 set_flag_from_ditem(diDesignerSaveHistory, module->defhistory);
  966.                 set_flag_from_ditem(diDesignerSaveCompress, module->compresslayers);
  967.                 /* Collect the file and path to save to. */
  968.                 SetPt(&pnt, 100, 100);
  969.                 sprintf(spbuf, "%s.g", namebuf);
  970.                 c2p(spbuf, tmpstr);
  971.                 SFPutFile(pnt, "\p", tmpstr, (DlgHookProcPtr) nil, &reply);
  972.                 if (reply.good) {
  973.                     /* Make the location of the file be the current volume. */
  974.                     SetVol(reply.fName, reply.vRefNum);
  975.                     p2c(((char *) reply.fName), namebuf);
  976.                     module->filename = copy_string(namebuf);
  977.                     SetCursor(*watchcursor);
  978.                     if (!write_game_module(module)) {
  979.                         run_warning("Couldn't write the module \"%s\"!", module->filename);
  980.                         /* Don't fall through, might be able to fix by changing save options. */
  981.                         break;
  982.                     }
  983.                     /* Mark as an Xconq game. */
  984.                     set_game_file_type(module->filename);
  985.                     SetCursor(&QD(arrow));
  986.                 } else {
  987.                     break;
  988.                 }
  989.                 /* Fall through to next case. */
  990.             case diDesignerSaveCancel:
  991.                 done = TRUE;
  992.                 break;
  993.             case diDesignerSaveTypes:
  994.             case diDesignerSaveTables:
  995.             case diDesignerSaveGlobals:
  996.             case diDesignerSaveWorld:
  997.             case diDesignerSaveAreas:
  998.             case diDesignerSaveAreaTerrain:
  999.             case diDesignerSaveAreaMisc:
  1000.             case diDesignerSaveAreaWeather:
  1001.             case diDesignerSaveAreaMaterial:
  1002.             case diDesignerSaveSides:
  1003.             case diDesignerSaveSideNames:
  1004.             case diDesignerSaveSideProps:
  1005.             case diDesignerSaveSideViews:
  1006.             case diDesignerSavePlayers:
  1007.             case diDesignerSaveUnits:
  1008.             case diDesignerSaveUnitIds:
  1009.             case diDesignerSaveUnitProps:
  1010.             case diDesignerSaveUnitMoves:
  1011.             case diDesignerSaveUnitPlans:
  1012.             case diDesignerSaveScoring:
  1013.             case diDesignerSaveHistory:
  1014.             case diDesignerSaveCompress:
  1015.                 /* Toggle check boxes. */
  1016.                 GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
  1017.                 SetCtlValue((ControlHandle) itemhandle,
  1018.                             !GetCtlValue((ControlHandle) itemhandle));
  1019.                 break;
  1020.             case diDesignerSaveModule:
  1021.                 /* (should bring up a dialog to set module properties) */
  1022.                 break;
  1023.             case diDesignerSaveReshape:
  1024.                 /* Bring up *another* modal dialog. */
  1025.                 designer_reshape_dialog(module);
  1026.                 break;
  1027.         }
  1028.     }
  1029.     DisposDialog(win);
  1030. }
  1031.  
  1032. /* A special dialog that allows for saving a world of different dimensions than is
  1033.    currently being used in the game. */
  1034.  
  1035. void
  1036. designer_reshape_dialog(Module *module)
  1037. {
  1038.     int done = FALSE;
  1039.     short ditem;
  1040.     WindowPtr win;
  1041.     Str255 tmpstr;
  1042.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1043.     
  1044.     win = GetNewDialog(dDesignerReshape, NULL, (DialogPtr) -1L);
  1045.     while (!done) {
  1046.         /* Deactivate the front window. */
  1047.         activate_window(FrontWindow(), FALSE);
  1048.           put_number_into_ditem(diDesignerReshapeOrigWidth, area.width);
  1049.           put_number_into_ditem(diDesignerReshapeOrigHeight, area.height);
  1050.           put_number_into_ditem(diDesignerReshapeOrigWorld, world.circumference);
  1051.           put_number_into_ditem(diDesignerReshapeOrigSubWidth, module->subareawidth);
  1052.           put_number_into_ditem(diDesignerReshapeOrigSubHeight, module->subareaheight);
  1053.           put_number_into_ditem(diDesignerReshapeOrigSubX, module->subareax);
  1054.           put_number_into_ditem(diDesignerReshapeOrigSubY, module->subareay);
  1055.           put_number_into_ditem(diDesignerReshapeOutputSubWidth, module->finalsubareawidth);
  1056.           put_number_into_ditem(diDesignerReshapeOutputSubHeight, module->finalsubareaheight);
  1057.           put_number_into_ditem(diDesignerReshapeOutputSubX, module->finalsubareax);
  1058.           put_number_into_ditem(diDesignerReshapeOutputSubY, module->finalsubareay);
  1059.           put_number_into_ditem(diDesignerReshapeOutputWidth, module->finalwidth);
  1060.           put_number_into_ditem(diDesignerReshapeOutputHeight, module->finalheight);
  1061.           put_number_into_ditem(diDesignerReshapeOutputWorld, module->finalcircumference);
  1062. /*          put_number_into_ditem(diDesignerReshapeFillTerrain, module->fillterrain); */
  1063.         SetCursor(&QD(arrow));
  1064.         ModalDialog(NULL, &ditem);
  1065.         switch (ditem) {
  1066.             case diDesignerReshapeOK:
  1067.                   get_number_from_ditem(diDesignerReshapeOrigSubWidth, module->subareawidth);
  1068.                   get_number_from_ditem(diDesignerReshapeOrigSubHeight, module->subareaheight);
  1069.                   get_number_from_ditem(diDesignerReshapeOrigSubX, module->subareax);
  1070.                   get_number_from_ditem(diDesignerReshapeOrigSubY, module->subareay);
  1071.                   get_number_from_ditem(diDesignerReshapeOutputSubWidth, module->finalsubareawidth);
  1072.                   get_number_from_ditem(diDesignerReshapeOutputSubHeight, module->finalsubareaheight);
  1073.                   get_number_from_ditem(diDesignerReshapeOutputSubX, module->finalsubareax);
  1074.                   get_number_from_ditem(diDesignerReshapeOutputSubY, module->finalsubareay);
  1075.                   get_number_from_ditem(diDesignerReshapeOutputWidth, module->finalwidth);
  1076.                   get_number_from_ditem(diDesignerReshapeOutputHeight, module->finalheight);
  1077.                   get_number_from_ditem(diDesignerReshapeOutputWorld, module->finalcircumference);
  1078. /*                  get_number_from_ditem(diDesignerReshapeFillTerrain, module->fillterrain);  */
  1079.                 /* Fall through to next case. */
  1080.             case diDesignerReshapeCancel:
  1081.                 done = TRUE;
  1082.                 break;
  1083.         }
  1084.     }
  1085.     DisposDialog(win);
  1086. }
  1087.  
  1088. #endif /* DESIGNERS */
  1089.