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

  1. /* Worlds and areas in Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. extern int num_features PARAMS ((void));
  12.  
  13. /* The main world structure. */
  14.  
  15. World world;
  16.  
  17. /* The current area of the world. */
  18.  
  19. Area area;
  20.  
  21. /* This is the number of terrain types that can fill a cell. */
  22.  
  23. int numcelltypes = 0;
  24.  
  25. /* This is the number of terrain types that can be border terrain. */
  26.  
  27. int numbordtypes = 0;
  28.  
  29. /* This is the number of types that can be connections. */
  30.  
  31. int numconntypes = 0;
  32.  
  33. /* This is the number of types that can be coatings. */
  34.  
  35. int numcoattypes = 0;
  36.  
  37. /* (Features could also be used to implement the region 
  38.    labeling scheme now used only in the machine player) */
  39.  
  40. Feature *featurelist = NULL;
  41.  
  42. Feature *last_feature = NULL;
  43.  
  44. /* Feature id 0 means no geographical feature defined. */
  45.  
  46. int nextfid = 1;
  47.  
  48. int minelev;
  49. int maxelev;
  50.  
  51. int mintemp;
  52. int maxtemp;
  53.  
  54. int any_temp_variation = FALSE;
  55.  
  56. int any_temp_variation_in_layer = FALSE;
  57.  
  58. int minwindforce;
  59. int maxwindforce;
  60.  
  61. int any_wind_variation = FALSE;
  62.  
  63. int any_wind_variation_in_layer = FALSE;
  64.  
  65. int minclouds;
  66. int maxclouds;
  67.  
  68. int any_clouds = FALSE;
  69.  
  70. /* This is true if it is ever possible to have quantities of material
  71.    in cells. */
  72.  
  73. int any_materials_in_terrain = FALSE;
  74.  
  75. static Feature *tmpfeature;
  76.  
  77. static int tmpint;
  78.  
  79. static int tmpint2, tmpint3;
  80.  
  81. /* Clean out all the world and area data. */
  82.  
  83. void
  84. init_world()
  85. {
  86.     memset(&world, 0, sizeof(World));
  87.     /* These default values effectively disable day and year effects. */
  88.     world.daylength = 1;
  89.     world.yearlength = 1;
  90.     /* Init the current (default) area. */
  91.     memset(&area, 0, sizeof(Area));
  92.     /* Note especially that area width and height dimensions are now zero. */
  93. }
  94.  
  95. int
  96. set_world_circumference(circum, warn)
  97. int circum, warn;
  98. {
  99.     /* All world circumferences are valid, no checks necessary. */
  100.     world.circumference = circum;
  101.     world.daylight_width = ((50 * world.circumference) / 100) / 2;
  102.     world.twilight_width = ((60 * world.circumference) / 100) / 2;
  103.     area.xwrap = (world.circumference == area.width);
  104.     return TRUE;
  105. }
  106.  
  107. int
  108. set_area_shape(width, height, warn)
  109. int width, height, warn;
  110. {
  111.     if (!valid_area_shape(width, height, warn))
  112.       return FALSE;
  113.     area.width = width;  area.height = height;
  114.     area.halfheight = area.height / 2;
  115.     area.maxdim = max(area.width, area.height);
  116.     area.xwrap = (world.circumference == area.width);
  117.     area.numcells = area.width * area.height;
  118.     if (!area.xwrap)
  119.       area.numcells = (area.numcells * 3) / 4;
  120.     return TRUE;
  121. }
  122.  
  123. int
  124. valid_area_shape(width, height, warn)    
  125. int width, height, warn;
  126. {
  127.     if (width < MINWIDTH || height < MINHEIGHT) {
  128.     if (warn)
  129.       init_warning("area is %dx%d, too small", width, height);
  130.         return FALSE;
  131.     }
  132.     if (width != world.circumference && width * 2 < height) {
  133.     if (warn)
  134.       init_warning("hexagon area is %dx%d, impossible dimensions",
  135.                width, height);
  136.         return FALSE;
  137.     }
  138.     return TRUE;
  139. }
  140.  
  141. void
  142. check_area_shape()
  143. {
  144.     if (area.width == 0 || area.height == 0)
  145.       run_error("0x0 area");
  146.     if (!valid_area_shape(area.width, area.height, TRUE))
  147.       run_error("sorry, this is a fatal error here");
  148. }
  149.  
  150. /* Calculate globals that we can use later to decide if particular
  151.    classes of calculations need to be done, such as weather changes. */
  152.  
  153. void
  154. calculate_world_globals()
  155. {
  156.     int t, m;
  157.  
  158.     /* This is a last chance to set a default world size.
  159.        Will usually be set already, by players or by module. */
  160.     if (area.width <= 0 && area.height <= 0)
  161.       set_area_shape(DEFAULTWIDTH, DEFAULTHEIGHT, 0);
  162.     minelev = t_elev_min(0);
  163.     maxelev = t_elev_max(0);
  164.     mintemp = t_temp_min(0);
  165.     maxtemp = t_temp_max(0);
  166.     minwindforce = t_wind_force_min(0);
  167.     maxwindforce = t_wind_force_max(0);
  168.     minclouds = t_clouds_min(0);
  169.     maxclouds = t_clouds_max(0);
  170.     for_all_terrain_types(t) {
  171.     if (t_elev_min(t) < minelev)
  172.       minelev = t_elev_min(t);
  173.     if (t_elev_max(t) > maxelev)
  174.       maxelev = t_elev_max(t);
  175.     if (t_temp_min(t) < mintemp)
  176.       mintemp = t_temp_min(t);
  177.     if (t_temp_max(t) > maxtemp)
  178.       maxtemp = t_temp_max(t);
  179.     if (t_wind_force_min(t) < maxwindforce)
  180.       minwindforce = t_wind_force_min(t);
  181.     if (t_wind_force_max(t) > maxwindforce)
  182.       maxwindforce = t_wind_force_max(t);
  183.     if (t_clouds_min(t) < minclouds)
  184.       minclouds = t_clouds_min(t);
  185.     if (t_clouds_max(t) > maxclouds)
  186.       maxclouds = t_clouds_max(t);    
  187.     /* Decide if materials can ever be accumulated in cells. */
  188.     for_all_material_types(m) {
  189.         if (tm_storage_x(t, m) > 0)
  190.           any_materials_in_terrain = TRUE;
  191.     }
  192.     }
  193.     if (mintemp != maxtemp)
  194.       any_temp_variation = TRUE;
  195.     if (minwindforce != maxwindforce)
  196.       any_wind_variation = TRUE;
  197.     /* (should figure out what this is supposed to mean really) */
  198.     if (minwindforce != maxwindforce)
  199.       any_wind_variation_in_layer = TRUE;
  200.     if (minclouds != maxclouds)
  201.       any_clouds = TRUE;
  202. }
  203.  
  204. void
  205. count_terrain_subtypes()
  206. {
  207.     int t;
  208.  
  209.     numcelltypes = numbordtypes = numconntypes = numcoattypes = 0;
  210.     for_all_terrain_types(t) {
  211.     switch (t_subtype(t)) {
  212.       case cellsubtype:
  213.         ++numcelltypes;
  214.         break;
  215.       case bordersubtype:
  216.         ++numbordtypes;
  217.         break;
  218.       case connectionsubtype:
  219.         ++numconntypes;
  220.         break;
  221.       case coatingsubtype:
  222.         ++numcoattypes;
  223.         break;
  224.     }
  225.     }
  226. }
  227.  
  228. void
  229. final_init_world()
  230. {
  231.     int x, y, el, count, sum, rowcount, rowsum, rowavg;
  232.  
  233.     area.minelev = area.maxelev = area.avgelev = 0;
  234.     if (elevations_defined()) {
  235.     area.maxelev = area.minelev = elev_at(area.width / 2, area.height / 2);
  236.     /* In order to avoid overflowing by summing all elevations at
  237.        once, we average along a row, then average the row averages. */
  238.     count = sum = 0;
  239.     for (y = 0; y < area.height; y++) {
  240.         rowcount = rowsum = 0;
  241.         for (x = 0; x < area.width; x++) {
  242.         if (in_area(x, y)) {
  243.             el = elev_at(x, y);
  244.             if (el < area.minelev)
  245.               area.minelev = el;
  246.             if (el > area.maxelev)
  247.               area.maxelev = el;
  248.             ++rowcount;
  249.             rowsum += el;
  250.         }
  251.         }
  252.         rowavg = rowsum / rowcount;
  253.         ++count;
  254.         sum += rowavg;
  255.     }
  256.     area.avgelev = sum / count;
  257.     }
  258.     /* Calculate extent and position of geographical features. */
  259.     compute_all_feature_centroids();
  260. }
  261.  
  262. /* Make space for an area's terrain, and for the unit cache. */
  263.  
  264. /* This can be postponed until it is actually needed. */
  265.  
  266. void
  267. allocate_area_terrain()
  268. {
  269.     check_area_shape();
  270.     /* Get rid of old stuff maybe. (is this desirable?) */
  271.     if (area.terrain != NULL) {
  272.     free((char *) area.terrain);
  273.     free((char *) area.units);
  274.     }
  275.     /* Allocate the basic terrain layer. */
  276.     /* It doesn't matter what ttype 0 is, we're guaranteed that it
  277.        will be defined eventually. */
  278.     area.terrain = malloc_area_layer(char);
  279.     /* Allocate and null out the unit cache. */
  280.     area.units = malloc_area_layer(Unit *);
  281. }
  282.  
  283. /* Set up the auxiliary terrain layer of the area. */
  284.  
  285. void
  286. allocate_area_aux_terrain(t)
  287. int t;
  288. {
  289.     if (!any_aux_terrain_defined()) {
  290.     area.auxterrain = (char **) xmalloc(numttypes * sizeof(char *));
  291.     }
  292.     if (!aux_terrain_defined(t)) {
  293.     area.auxterrain[t] = malloc_area_layer(char);
  294.     }
  295. }
  296.  
  297. /* Allocate some number of scratch layers.  These are used as temporaries
  298.    in calculations, etc. */
  299.  
  300. void
  301. allocate_area_scratch(n)
  302. int n;
  303. {
  304.     check_area_shape();
  305.     if (n >= 1 && !area.tmp1) {
  306.     area.tmp1 = malloc_area_layer(short);
  307.     }
  308.     if (n >= 2 && !area.tmp2) {
  309.     area.tmp2 = malloc_area_layer(short);
  310.     }
  311.     if (n >= 3 && !area.tmp3) {
  312.     area.tmp3 = malloc_area_layer(short);
  313.     }
  314.     if (n >= 4) {
  315.     run_error("can't allocate more than 3 scratch layers");
  316.     }
  317. }
  318.  
  319. /* Should have something to free scratch layers up also maybe. */
  320.  
  321. /* Allocate and init the elevation layer. */
  322.  
  323. void
  324. allocate_area_elevations()
  325. {
  326.     if (!elevations_defined()) {
  327.     check_area_shape();
  328.     area.elevations = malloc_area_layer(short);
  329.     }
  330. }
  331.  
  332. /* Allocate and init the temperature layer. */
  333.  
  334. void
  335. allocate_area_temperatures()
  336. {
  337.     if (!temperatures_defined()) {
  338.     check_area_shape();
  339.     area.temperature = malloc_area_layer(short);
  340.     }
  341.     /* We'll need one scratch layer too. */
  342.     allocate_area_scratch(1);
  343. }
  344.  
  345. /* Allocate a layer indicating the side of the people living in each cell. */
  346.  
  347. void
  348. allocate_area_people_sides()
  349. {
  350.     if (!people_sides_defined()) {
  351.     check_area_shape();
  352.     area.peopleside = malloc_area_layer(char);
  353.     /* NOBODY != 0, so need to blast it over the layer. */
  354.     memset(area.peopleside, NOBODY, area.width * area.height);
  355.     }
  356. }
  357.  
  358. /* Set up a cell material layer of the area. */
  359.  
  360. void
  361. allocate_area_material(m)
  362. int m;
  363. {
  364.     check_area_shape();
  365.     if (!any_cell_materials_defined()) {
  366.     area.materials = (short **) xmalloc(nummtypes * sizeof(short *));
  367.     }
  368.     if (!cell_material_defined(m)) {
  369.     area.materials[m] = malloc_area_layer(short);
  370.     }
  371. }
  372.  
  373. void
  374. allocate_area_clouds()
  375. {
  376.     if (!clouds_defined()) {
  377.     check_area_shape();
  378.     area.clouds = malloc_area_layer(short);
  379.     }
  380. }
  381.  
  382. void
  383. allocate_area_cloud_altitudes()
  384. {
  385.     allocate_area_cloud_bottoms();
  386.     allocate_area_cloud_heights();
  387. }
  388.  
  389. void
  390. allocate_area_cloud_bottoms()
  391. {
  392.     if (!cloud_bottoms_defined()) {
  393.     check_area_shape();
  394.     area.cloudbottoms = malloc_area_layer(short);
  395.     }
  396. }
  397.  
  398. void
  399. allocate_area_cloud_heights()
  400. {
  401.     if (!cloud_heights_defined()) {
  402.     check_area_shape();
  403.     area.cloudheights = malloc_area_layer(short);
  404.     }
  405. }
  406.  
  407. void
  408. allocate_area_winds()
  409. {
  410.     if (!winds_defined()) {
  411.     check_area_shape();
  412.     area.winds = malloc_area_layer(short);
  413.     }
  414. }
  415.  
  416. int
  417. fn_terrain_at(x, y)
  418. int x, y;
  419. {
  420.     return terrain_at(x, y);
  421. }
  422.  
  423. int
  424. fn_aux_terrain_at(x, y)
  425. int x, y;
  426. {
  427.     return aux_terrain_at(x, y, tmpttype);
  428. }
  429.  
  430. int
  431. fn_feature_at(x, y)
  432. int x, y;
  433. {
  434.     return raw_feature_at(x, y);
  435. }
  436.  
  437. int
  438. fn_elevation_at(x, y)
  439. int x, y;
  440. {
  441.     return elev_at(x, y);
  442. }
  443.  
  444. int
  445. fn_people_side_at(x, y)
  446. int x, y;
  447. {
  448.     return people_side_at(x, y);
  449. }
  450.  
  451. int
  452. fn_material_at(x, y)
  453. int x, y;
  454. {
  455.     return material_at(x, y, tmpmtype);
  456. }
  457.  
  458. int
  459. fn_temperature_at(x, y)
  460. int x, y;
  461. {
  462.     return temperature_at(x, y);
  463. }
  464.  
  465. int
  466. fn_raw_cloud_at(x, y)
  467. int x, y;
  468. {
  469.     return raw_cloud_at(x, y);
  470. }
  471.  
  472. int
  473. fn_raw_cloud_bottom_at(x, y)
  474. int x, y;
  475. {
  476.     return raw_cloud_bottom_at(x, y);
  477. }
  478.  
  479. int
  480. fn_raw_cloud_height_at(x, y)
  481. int x, y;
  482. {
  483.     return raw_cloud_height_at(x, y);
  484. }
  485.  
  486. int
  487. fn_raw_wind_at(x, y)
  488. int x, y;
  489. {
  490.     return raw_wind_at(x, y);
  491. }
  492.  
  493. void
  494. fn_set_terrain_at(x, y, val)
  495. int x, y, val;
  496. {
  497.     extern warnbadterrain, numbadterrain;
  498.  
  499.     /* It's important not to put bad values into the terrain layer. */
  500.     if (!is_terrain_type(val)) {
  501.         /* Only warn the first few times, just count thereafter. */
  502.         if (warnbadterrain && numbadterrain < 10) {
  503.         read_warning("Unknown terrain type (%d) at %d,%d; substituting %s",
  504.              val, x, y, t_type_name(0));
  505.     }
  506.     val = 0;
  507.     ++numbadterrain;
  508.     }
  509.     set_terrain_at(x, y, val);
  510. }
  511.  
  512. void
  513. fn_set_aux_terrain_at(x, y, val)
  514. int x, y, val;
  515. {
  516.     /* Filter anything but the basic six bits. */
  517.     val &= 0x3f;
  518.     set_aux_terrain_at(x, y, tmpttype, val);
  519. }
  520.  
  521. void
  522. fn_set_people_side_at(x, y, val)
  523. int x, y, val;
  524. {
  525.     set_people_side_at(x, y, val);
  526. }
  527.  
  528. void
  529. fn_set_raw_feature_at(x, y, val)
  530. int x, y, val;
  531. {
  532.     set_raw_feature_at(x, y, val);
  533. }
  534.  
  535. void
  536. fn_set_elevation_at(x, y, val)
  537. int x, y, val;
  538. {
  539.     set_elev_at(x, y, val);
  540. }
  541.  
  542. void
  543. fn_set_material_at(x, y, val)
  544. int x, y, val;
  545. {
  546.     set_material_at(x, y, tmpmtype, val);
  547. }
  548.  
  549. void
  550. fn_set_temperature_at(x, y, val)
  551. int x, y, val;
  552. {
  553.     set_temperature_at(x, y, val);
  554. }
  555.  
  556. void
  557. fn_set_raw_wind_at(x, y, val)
  558. int x, y, val;
  559. {
  560.     set_raw_wind_at(x, y, val);
  561. }
  562.  
  563. void
  564. fn_set_raw_cloud_at(x, y, val)
  565. int x, y, val;
  566. {
  567.     set_raw_cloud_at(x, y, val);
  568. }
  569.  
  570. void
  571. fn_set_raw_cloud_bottom_at(x, y, val)
  572. int x, y, val;
  573. {
  574.     set_raw_cloud_bottom_at(x, y, val);
  575. }
  576.  
  577. void
  578. fn_set_raw_cloud_height_at(x, y, val)
  579. int x, y, val;
  580. {
  581.     set_raw_cloud_height_at(x, y, val);
  582. }
  583.  
  584. /* Change the terrain of the cell at the given location to the given
  585.    type of terrain, and update everything affected by the change. */
  586.  
  587. void
  588. change_terrain_type(x, y, t2)
  589. int x, y, t2;
  590. {
  591.     int t, curview, newview, update, u2, nu2;
  592.     HistEventType hevttype;
  593.     Unit *unit2;
  594.     Side *side;
  595.  
  596.     t = terrain_at(x, y);
  597.     set_terrain_at(x, y, t2);
  598.     /* Let everybody see this change. */
  599.     for_all_sides(side) {
  600.     update = FALSE;
  601.     if (side->see_all) {
  602.         update = TRUE;
  603.     } else if (cover(side, x, y) > 0) {
  604.         /* Always update our knowledge of the terrain. */
  605.         curview = terrain_view(side, x, y);
  606.         newview = buildtview(t2);
  607.         set_terrain_view(side, x, y, newview);
  608.         if (!g_see_terrain_always())
  609.           set_terrain_view_date(side, x, y, g_turn());
  610.         if (newview != curview)
  611.           update = TRUE;
  612.     }
  613.     if (update) {
  614.         update_cell_display(side, x, y, TRUE);
  615.     }
  616.     }
  617.     /* There might be catastrophic consequences for any units here. */
  618.     for_all_stack(x, y, unit2) {
  619.     u2 = unit2->type;
  620.     if (ut_vanishes_on(u2, t2)
  621.         && !can_occupy_conn(unit2, unit2->x, unit2->y, unit2->z)) {
  622.         hevttype = H_UNIT_VANISHED;
  623.         kill_unit(unit2, hevttype);
  624.     } else if (ut_wrecks_on(u2, t2)
  625.            && !can_occupy_conn(unit2, unit2->x, unit2->y, unit2->z)) {
  626.         if (u_wrecked_type(u2) == NONUTYPE) {
  627.         /* Occupants always die if the wrecked unit disappears. */
  628.         hevttype = H_UNIT_WRECKED;
  629.         kill_unit(unit2, hevttype);
  630.         } else {
  631.         /* Change the unit's type. */
  632.         hevttype = H_UNIT_WRECKED;
  633.         change_unit_type(unit2, u_wrecked_type(u2), hevttype);
  634.         nu2 = unit2->type;
  635.         /* Restore to default hp for the new type. */
  636.         unit2->hp = unit2->hp2 = u_hp(nu2);
  637.         /* Get rid of occupants if now overfull. */
  638.         eject_excess_occupants(unit2);
  639.         /* Maybe make it go away, taking remaining unlucky
  640.                    occupants with. */
  641.         if (ut_vanishes_on(nu2, t2)) {
  642.             hevttype = H_UNIT_VANISHED;
  643.             kill_unit(unit2, hevttype);
  644.         }
  645.         }
  646.     }
  647.     if (active_display(unit2->side)) {
  648.         if (hevttype == H_UNIT_VANISHED) {
  649.         notify(unit2->side, "Terrain change from %s to %s causes %s to vanish",
  650.                t_type_name(t), t_type_name(t2),
  651.                unit_handle(unit2->side, unit2));
  652.         } else if (hevttype == H_UNIT_WRECKED) {
  653.         notify(unit2->side, "Terrain change from %s to %s wrecks %s",
  654.                t_type_name(t), t_type_name(t2),
  655.                unit_handle(unit2->side, unit2));
  656.         }
  657.     }
  658.     }
  659. }
  660.  
  661. /* Generalized area search routine.  It starts in the immediately adjacent
  662.    cells and expands outwards.  The basic structure is to examine successive
  663.    "rings" out to the max distance; within each ring, we must scan each of
  664.    six faces (picking a random one to start with) by iterating along that
  665.    face, in a direction 120 degrees from the direction out to one corner of
  666.    the face.  Draw a picture if you want to understand it... */
  667.  
  668. /* Incr is normally one.  It is set to area_size to search on areas
  669.    instead of cells. */
  670.  
  671. /* Note that points far outside the map may be generated, but the predicate
  672.    will not be called on them.  It may be applied to the same point several
  673.    times, however, if the distance is enough to wrap around the area. */
  674.  
  675. /* This needs to be changed to understand different world shapes. */
  676.  
  677. int
  678. search_around(x0, y0, maxdist, pred, rxp, ryp, incr)
  679. int x0, y0, maxdist, (*pred) PARAMS ((int, int)), *rxp, *ryp, incr;
  680. {
  681.     int clockwise, dist, dd, d, dir, x1, y1, i, dir2, x, y, xw;
  682.  
  683.     maxdist = max(min(maxdist, area.width), min(maxdist, area.height));
  684.     clockwise = (flip_coin() ? 1 : -1);
  685.     for (dist = 1; dist <= maxdist; dist += incr) {
  686.     dd = random_dir();
  687.     for_all_directions(d) {
  688.         dir = (d + dd) % NUMDIRS;
  689.         x1 = x0 + dist * dirx[dir];
  690.         y1 = y0 + dist * diry[dir];
  691.         for (i = 0; i < dist; ++i) {
  692.         dir2 = opposite_dir(dir + clockwise);
  693.         x = x1 + i * dirx[dir2] * incr;
  694.         y = y1 + i * diry[dir2] * incr;
  695.         xw = wrapx(x);
  696.         if (inside_area(x, y) && (*pred)(xw, y)) {
  697.             *rxp = xw;  *ryp = y;
  698.             return TRUE;
  699.         }
  700.         }
  701.     }
  702.     }
  703.     return FALSE;
  704. }
  705.  
  706. int
  707. search_and_apply(x0, y0, maxdist, pred, rxp, ryp, incr, fn, num)
  708. int x0, y0, maxdist, *rxp, *ryp, incr, num;
  709. int (*pred) PARAMS ((int, int));
  710. void (*fn) PARAMS ((int, int));
  711. {
  712.     int clockwise, dist, x0w, dd, d, dir, x1, y1, i, dir2, x, y, xw;
  713.  
  714.     maxdist = max(min(maxdist, area.width), min(maxdist, area.height));
  715.     clockwise = (flip_coin() ? 1 : -1);
  716.     if (maxdist >= 0) {
  717.     x0w = wrapx(x0);
  718.     if (inside_area(x0w, y0) && (*pred)(x0w, y0)) {
  719.         *rxp = x0w;  *ryp = y0;
  720.         (*fn)(x0w, y0);
  721.         if (--num <= 0)
  722.           return TRUE;
  723.     }
  724.     }
  725.     for (dist = 1; dist <= maxdist; dist += incr) {
  726.     dd = random_dir();
  727.     for_all_directions(d) {
  728.         dir = (d + dd) % NUMDIRS;
  729.         x1 = x0 + dist * dirx[dir];
  730.         y1 = y0 + dist * diry[dir];
  731.         for (i = 0; i < dist; ++i) {
  732.         dir2 = opposite_dir(dir + clockwise);
  733.         x = x1 + i * dirx[dir2] * incr;
  734.         y = y1 + i * diry[dir2] * incr;
  735.         if (between(0, y, area.height-1)) {
  736.             xw = wrapx(x);
  737.             if (inside_area(x, y) && (*pred)(xw, y)) {
  738.             *rxp = xw;  *ryp = y;
  739.             (*fn)(xw, y);
  740.             if (--num <= 0)
  741.               return TRUE;
  742.             }
  743.         }
  744.         }
  745.     }
  746.     }
  747.     return FALSE;
  748. }
  749.  
  750. /* Apply a function to every cell within the given radius, being careful (for
  751.    both safety and efficiency reasons) not to go past edges.  Note that the
  752.    distance is inclusive, and that distance of 0 means x0,y0 only.  Also,
  753.    if the distance is greater than either map dimension, this routine still
  754.    operates on a correct intersection with the area.  */
  755.  
  756. int stop_apply;
  757.  
  758. void
  759. apply_to_area(x0, y0, dist, fn)
  760. int x0, y0, dist;
  761. void (*fn) PARAMS ((int, int));
  762. {
  763.     int x, y, x1, y1, x2, y2;
  764.  
  765.     dist = min(dist, area.maxdim);
  766.     y1 = y0 - dist;
  767.     y2 = y0 + dist;
  768.     stop_apply = FALSE;
  769.     for (y = y1; y <= y2; ++y) {
  770.     if (between(1, y, area.height-2)) {
  771.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  772.         x1 = x0 - (y < y0 ? (y - y1) : dist);
  773.         x2 = x0 + (y > y0 ? (y2 - y) : dist);
  774.         for (x = x1; x <= x2; ++x) {
  775.         /* not real efficient, sigh... */
  776.         if (in_area(wrapx(x), y)) {
  777.             ((*fn)(wrapx(x), y));
  778.             /* Backdoor for early termination. */
  779.             if (stop_apply)
  780.               return;
  781.         }
  782.         }
  783.     }
  784.     }
  785. }
  786.  
  787. void
  788. apply_to_area_plus_edge(x0, y0, dist, fn)
  789. int x0, y0, dist;
  790. void (*fn) PARAMS ((int, int));
  791. {
  792.     int x, y, x1, y1, x2, y2;
  793.  
  794.     dist = min(dist, area.maxdim);
  795.     y1 = y0 - dist;
  796.     y2 = y0 + dist;
  797.     for (y = y1; y <= y2; ++y) {
  798.     if (between(0, y, area.height-1)) {
  799.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  800.         x1 = x0 - (y < y0 ? (y - y1) : dist);
  801.         x2 = x0 + (y > y0 ? (y2 - y) : dist);
  802.         for (x = x1; x <= x2; ++x) {
  803.         /* not real efficient, sigh... */
  804.         if (in_area(wrapx(x), y)) {
  805.             ((*fn)(wrapx(x), y));
  806.         }
  807.         }
  808.     }
  809.     }
  810. }
  811.  
  812. void
  813. apply_to_ring(x0, y0, distmin, distmax, fn)
  814. int x0, y0, distmin, distmax;
  815. void (*fn) PARAMS ((int, int));
  816. {
  817.     int dist, x, y, x1, y1, x2, y2;
  818.  
  819.     dist = min(distmax, area.maxdim);
  820.     y1 = y0 - dist;
  821.     y2 = y0 + dist;
  822.     for (y = y1; y <= y2; ++y) {
  823.     if (between(1, y, area.height-2)) {
  824.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  825.         x1 = x0 - (y < y0 ? (y - y1) : dist);
  826.         x2 = x0 + (y > y0 ? (y2 - y) : dist);
  827.         for (x = x1; x <= x2; ++x) {
  828.         /* not real efficient, sigh... */
  829.         if (in_area(wrapx(x), y) && distance(x, y, x0, y0) >= distmin) {
  830.             ((*fn)(wrapx(x), y));
  831.         }
  832.         }
  833.     }
  834.     }
  835. }
  836.  
  837. /* Apply the function to the hexagon bounded by w,h. */
  838.  
  839. void
  840. apply_to_hexagon(x0, y0, w2, h2, fn)
  841. int x0, y0, w2, h2;
  842. void (*fn) PARAMS ((int, int));
  843. {
  844.     int x, y, x1, y1, x2, y2;
  845.  
  846.     y1 = limit(y0 - h2);
  847.     y2 = limit(y0 + h2);
  848.     for (y = y1; y <= y2; ++y) {
  849.     if (between(0, y, area.height-1)) {  /* always true? */
  850.         /* Compute endpoints of row, but don't wrap or loop will confuse */
  851.         x1 = x0 - w2 + (y < y0 ? (y0 - y) : 0);
  852.         x2 = x0 + w2 - (y > y0 ? (y - y0) : 0);
  853.         for (x = x1; x <= x2; ++x) {
  854.         /* not real efficient, sigh... */
  855.         if (in_area(wrapx(x), y)) {
  856.             ((*fn)(wrapx(x), y));
  857.         }
  858.         }
  859.     }
  860.     }
  861. }
  862.  
  863. /* Apply a function all along a path. */
  864.  
  865. void
  866. apply_to_path(fx, fy, tx, ty, dirtest, dirsort, fn, shortest)
  867. int fx, fy, tx, ty, shortest;
  868. int (*dirtest) PARAMS ((int x, int y, int dir));
  869. int (*dirsort) PARAMS ((int x, int y, int *dirchoices, int numchoices));
  870. int (*fn) PARAMS ((int x, int y, int dir, int j, int numchoices));
  871. {
  872.     int i = 500, j, x = fx, y = fy, moved;
  873.     int dx, dxa, dy, dirchoices[NUMDIRS], axis, hextant, tmp, sig;
  874.     int d1, d2, d3, d4;
  875.     int numchoices, shortestnumchoices;
  876.  
  877.     while (!(x == tx && y == ty) && i-- > 0 /* safety */) {
  878.     dx = tx - x;  dy = ty - y;
  879.     /* If in a wrapping world, choose the shortest of directions. */
  880.     if (area.xwrap) {
  881.         dxa = (tx + area.width) - fx;
  882.         if (ABS(dx) > ABS(dxa))
  883.           dx = dxa;
  884.         dxa = (tx - area.width) - fx;
  885.         if (ABS(dx) > ABS(dxa))
  886.           dx = dxa;
  887.     }
  888.     /* Figure out the axis or hextant of this delta. */
  889.     axis = hextant = -1;
  890.     /* Decode the delta values. */
  891.     if (dx == 0) {
  892.         axis = (dy > 0 ? NORTHEAST : SOUTHWEST);
  893.     } else if (dy == 0) {
  894.         axis = (dx > 0 ? EAST : WEST);
  895.     } else if (dx == (0 - dy)) {
  896.         axis = (dy > 0 ? NORTHWEST : SOUTHEAST);
  897.     } else if (dx > 0) {
  898.         hextant = (dy > 0 ? EAST :
  899.                (ABS(dx) > ABS(dy) ? SOUTHEAST : SOUTHWEST));
  900.     } else {
  901.         hextant = (dy < 0 ? WEST :
  902.                (ABS(dx) > ABS(dy) ? NORTHWEST : NORTHEAST));
  903.     }
  904.     numchoices = 0;
  905.     /* On an axis, there's no choice. */
  906.     if (axis >= 0) {
  907.         d1 = d2 = axis;
  908.         if (dirtest == NULL || (*dirtest)(x, y, d1))
  909.           dirchoices[numchoices++] = axis;
  910.     }
  911.     /* Two choices in the middle of a hextant. */
  912.     if (hextant >= 0) {
  913.         d1 = left_dir(hextant);
  914.         d2 = hextant;
  915.         if (dirtest == NULL || (*dirtest)(x, y, d1))
  916.           dirchoices[numchoices++] = d1;
  917.         if (dirtest == NULL || (*dirtest)(x, y, d2))
  918.           dirchoices[numchoices++] = d2;
  919.     }
  920.     /* Sort the choices if requested. */
  921.     if (numchoices > 1 && dirsort != NULL)
  922.       numchoices = (*dirsort)(x, y, dirchoices, numchoices);
  923.     /* Try each of the directions. */
  924.     if (!inside_area(x, y))
  925.       return;
  926.     moved = FALSE;
  927.     for (j = 0; j < numchoices; ++j) {
  928.         sig = (*fn)(x, y, dirchoices[j], j, numchoices);
  929.         if (sig > 0) {
  930.         /* It's cool - go with this dir. */
  931.         /* Jump along to the new spot on the path. */
  932.         x += dirx[dirchoices[j]];  y += diry[dirchoices[j]];
  933.         moved = TRUE;
  934.         /* Out of the loop. */
  935.         break;
  936.         } else if (sig < 0) {
  937.         /* Stop applying to the path right now. */
  938.         return;
  939.         } else {
  940.         /* Try another. */
  941.         }
  942.     }
  943.     /* If we don't have to pick a shortest path, we have two more
  944.        directions to try if we need to. */
  945.     if (!moved && !shortest) {
  946.         shortestnumchoices = numchoices;
  947.         d3 = left_dir(d1);
  948.         d4 = right_dir(d2);
  949.         if (dirtest == NULL || (*dirtest)(x, y, d3))
  950.           dirchoices[numchoices++] = d3;
  951.         if (dirtest == NULL || (*dirtest)(x, y, d4))
  952.           dirchoices[numchoices++] = d4;
  953.         if (numchoices > shortestnumchoices + 1 && dirsort != NULL)
  954.           (*dirsort)(x, y, dirchoices + shortestnumchoices, numchoices - shortestnumchoices);
  955.         /* Try each of the directions. */
  956.         for (j = shortestnumchoices; j < numchoices; ++j) {
  957.         sig = (*fn)(x, y, dirchoices[j], j, numchoices - shortestnumchoices);
  958.         if (sig > 0) {
  959.             /* It's cool - go with this dir. */
  960.             /* Jump along to the new spot on the path. */
  961.             x += dirx[dirchoices[j]];  y += diry[dirchoices[j]];
  962.             /* Out of the loop. */
  963.             break;
  964.         } else if (sig < 0) {
  965.             /* Stop applying to the path right now. */
  966.             return;
  967.         } else {
  968.             /* Try another. */
  969.         }
  970.         }
  971.     }
  972.     }
  973. }
  974.  
  975. #if 0 /* currently unused */
  976. /* Find a path between the two given points. */
  977.  
  978. /* The chooser function gets passed an small array for directions;
  979.    it is expected to fill it with directions sorted in order of
  980.    preference, and to return the number of directions it found. */
  981.  
  982. /* (the chooser also needs to respect already-marked cells) */
  983. /* (marking should account for all directions in?) */
  984. /* (should return a "figure of merit" sometimes) */
  985. /* (main prog should test vicinity of dest, might not be reachable
  986.    anyway, but maybe should have "reach within n cells") */
  987.  
  988. int
  989. find_path(fx, fy, tx, ty, chooser, maxwps, waypoints, numwpsp)
  990. int fx, fy, tx, ty, maxwps, *numwpsp;
  991. int (*chooser) PARAMS ((int, int, int, int, int *));
  992. Waypoint *waypoints;
  993. {
  994.     int ndirs, trythese[NUMDIRS], i;
  995.     int x1, y1, x2, y2;
  996.  
  997.     if (fx == fy && tx == ty) {
  998.     return TRUE;
  999.     }
  1000.     ndirs = (*chooser)(x1, y1, x2, y2, trythese);
  1001.     if (ndirs == 0) {
  1002.     /* We're totally blocked. */
  1003.     return FALSE;
  1004.     } else {
  1005.     for (i = 0; i < ndirs; ++i) {
  1006.         /* try this direction with find_path_aux */
  1007.     }
  1008.     }
  1009.     return FALSE;
  1010. }
  1011. #endif
  1012.  
  1013. #if 0        
  1014. /* Find the type of the border on the given side of the given hex. */
  1015.  
  1016. int
  1017. border_at(x, y, dir, t)
  1018. int x, y, dir, t;
  1019. {
  1020.     int bord;
  1021.  
  1022.     if (!inside_area(x, y)
  1023.     || !t_is_border(t)
  1024.     || !aux_terrain_defined(t))
  1025.       return FALSE;
  1026.     bord = aux_terrain_at(x, y, t);
  1027.     return (bord & (1 << dir));
  1028. }
  1029. #endif
  1030.  
  1031. /* For now, set a bit on both sides of a border. */
  1032.  
  1033. void
  1034. set_border_at(x, y, dir, t, onoff)
  1035. int x, y, dir, t, onoff;
  1036. {
  1037.     int ox, oy, bord, obord;
  1038.     int odir = opposite_dir(dir);
  1039.  
  1040.     if (!t_is_border(t))
  1041.       return;
  1042.     if (!point_in_dir(x, y, dir, &ox, &oy)) {
  1043.     run_warning("border on outside of world at %d,%d, can't set", x, y);
  1044.     return;
  1045.     }
  1046.     allocate_area_aux_terrain(t);
  1047.     onoff = (onoff ? 1 : 0);  /* make sure it's one bit */
  1048.     bord = aux_terrain_at(x, y, t);
  1049.     bord = ((onoff << dir) | (bord & ~(1 << dir)));
  1050.     set_aux_terrain_at(x, y, t, bord);
  1051.     /* Go to the other cell and tweak its border bits. */
  1052.     obord = aux_terrain_at(ox, oy, t);
  1053.     obord = ((onoff << odir) | (obord & ~(1 << odir)));
  1054.     set_aux_terrain_at(ox, oy, t, obord);
  1055. }
  1056.  
  1057. #if 0
  1058. /* Find the type of the connection on the given side of the given cell. */
  1059.  
  1060. int
  1061. connection_at(x, y, dir, t)
  1062. int x, y, dir, t;
  1063. {
  1064.     int conn;
  1065.  
  1066.     if (!inside_area(x, y)
  1067.     || !t_is_connection(t)
  1068.     || !aux_terrain_defined(t))
  1069.       return FALSE;
  1070.     conn = aux_terrain_at(x, y, t);
  1071.     return (conn & (1 << dir));
  1072. }
  1073. #endif
  1074.  
  1075. /* For now, set a bit on both sides of a connection. */
  1076.  
  1077. void
  1078. set_connection_at(x, y, dir, t, onoff)
  1079. int x, y, dir, t, onoff;
  1080. {
  1081.     int ox, oy, conn, oconn;
  1082.     int odir = opposite_dir(dir);
  1083.  
  1084.     if (!t_is_connection(t))
  1085.       return;
  1086.     if (!point_in_dir(x, y, dir, &ox, &oy)) {
  1087.     run_warning("connection to outside of world at %d,%d, can't set", x, y);
  1088.     return;
  1089.     }
  1090.     allocate_area_aux_terrain(t);
  1091.     onoff = (onoff ? 1 : 0);  /* make sure it's one bit */
  1092.     conn = aux_terrain_at(x, y, t);
  1093.     conn = ((onoff << dir) | (conn & ~(1 << dir)));
  1094.     set_aux_terrain_at(x, y, t, conn);
  1095.     /* Go to the other cell and tweak its connection bits. */
  1096.     oconn = aux_terrain_at(ox, oy, t);
  1097.     oconn = ((onoff << odir) | (oconn & ~(1 << odir)));
  1098.     set_aux_terrain_at(ox, oy, t, oconn);
  1099. }
  1100.  
  1101. /* If there might be any inconsistencies in borders or connections,
  1102.    this fixes them.  Basically this just detects if a bit is set on
  1103.    either side, and sets the bits on both sides if so. */
  1104.  
  1105. void
  1106. patch_linear_terrain(t)
  1107. int t;
  1108. {
  1109.     int x, y, dir, x1, y1;
  1110.     
  1111.     if (t_is_border(t)) {
  1112.     for_all_cells(x, y) {
  1113.         /* This test is a hack to save some time.  If a cell has no border
  1114.            flags in any direction, then either it has no borders or else it
  1115.            will be fixed up later on, when an adjacent cell is patched. */
  1116.         if (aux_terrain_at(x, y, t) != 0) {
  1117.         for_all_directions(dir) {
  1118.             if (border_at(x, y, dir, t)
  1119.             && point_in_dir(x, y, dir, &x1, &y1)
  1120.             && !border_at(x1, y1, opposite_dir(dir), t))
  1121.               set_border_at(x, y, dir, t, TRUE);
  1122.         }
  1123.         }
  1124.     }
  1125.     } else if (t_is_connection(t)) {
  1126.     for_all_cells(x, y) {
  1127.         if (aux_terrain_at(x, y, t) != 0) {
  1128.         for_all_directions(dir) {
  1129.             if (connection_at(x, y, dir, t)
  1130.             && point_in_dir(x, y, dir, &x1, &y1)
  1131.             && !connection_at(x1, y1, opposite_dir(dir), t))
  1132.               set_connection_at(x, y, dir, t, TRUE);
  1133.         }
  1134.         }
  1135.     }
  1136.     }
  1137. }
  1138.  
  1139. /* Make space to record named features. */
  1140.  
  1141. void
  1142. init_features()
  1143. {
  1144.     if (features_defined())
  1145.       return;
  1146.     featurelist = last_feature = NULL;
  1147.     area.features = malloc_area_layer(short);
  1148.     /* No need to fill layer with default value, as long as
  1149.        feature 0 means "no feature". */
  1150. }
  1151.  
  1152. Feature *
  1153. create_feature(typename, name)
  1154. char *typename, *name;
  1155. {
  1156.     Feature *newfeature = (Feature *) xmalloc(sizeof(Feature));
  1157.  
  1158.     newfeature->id = nextfid++;
  1159.     newfeature->typename = typename;
  1160.     newfeature->name = name;
  1161.     /* Add to the end of the feature list. */
  1162.     if (last_feature != NULL) {
  1163.         last_feature->next = newfeature;
  1164.     } else {
  1165.         featurelist = newfeature;
  1166.     }
  1167.     last_feature = newfeature;
  1168.     return newfeature;
  1169. }
  1170.  
  1171. Feature *
  1172. find_feature(fid)
  1173. int fid;
  1174. {
  1175.     Feature *feature;
  1176.  
  1177.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1178.     if (feature->id == fid)
  1179.       return feature;
  1180.     }
  1181.     return NULL;
  1182. }
  1183.  
  1184. Feature *
  1185. feature_at(x, y)
  1186. int x, y;
  1187. {
  1188.     int fid;
  1189.  
  1190.     if (!features_defined())
  1191.       return NULL;
  1192.  
  1193.     fid = raw_feature_at(x, y);
  1194.     if (fid == 0) {
  1195.     return NULL;
  1196.     } else {
  1197.     return find_feature(fid);
  1198.     }
  1199. }
  1200.  
  1201. void
  1202. set_feature_type_name(feature, typename)
  1203. Feature *feature;
  1204. char *typename;
  1205. {
  1206.     if (feature == NULL)
  1207.       return;
  1208.     feature->typename = copy_string(typename);
  1209.     /* (should ping all displays) */
  1210. }
  1211.  
  1212. void
  1213. set_feature_name(feature, name)
  1214. Feature *feature;
  1215. char *name;
  1216. {
  1217.     if (feature == NULL)
  1218.       return;
  1219.     feature->name = copy_string(name);
  1220.     /* (should ping all displays) */
  1221. }
  1222.  
  1223. void
  1224. destroy_feature(feature)
  1225. Feature *feature;
  1226. {
  1227.     Feature *tmp, *prev = NULL;
  1228.  
  1229.     if (feature == NULL)
  1230.       return; /* (should be error?) */
  1231.     if (feature == featurelist)
  1232.       featurelist = feature->next;
  1233.     else {
  1234.     for (tmp = featurelist; tmp != NULL; tmp = tmp->next) {
  1235.             if (tmp == feature) {
  1236.         if (prev != NULL)
  1237.           prev->next = tmp->next;
  1238.         break;
  1239.         }
  1240.     }
  1241.     prev = tmp;
  1242.     }
  1243.     /* (should dealloc also?) */
  1244. }
  1245.  
  1246. /* (should be able to call this from designer tools) */
  1247.  
  1248. void
  1249. renumber_features()
  1250. {
  1251.     int newfid = 1, maxoldfid = 0, x, y;
  1252.     short *newlabels;
  1253.     Feature *feature;
  1254.  
  1255.     if (!features_defined())
  1256.       return;
  1257.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1258.         maxoldfid = max(maxoldfid, feature->id);
  1259.         feature->relabel = newfid++;
  1260.     }
  1261.     if (maxoldfid > 1000)
  1262.       return; /* don't risk it */
  1263.     newlabels = (short *) xmalloc((maxoldfid + 1) * sizeof(short));
  1264.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1265.         newlabels[feature->id] = feature->relabel;
  1266.     }
  1267.     for_all_cells(x, y) {
  1268.         set_raw_feature_at(x, y, newlabels[raw_feature_at(x, y)]);
  1269.     }
  1270.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1271.         feature->id = feature->relabel;
  1272.     }
  1273. }
  1274.  
  1275. void
  1276. compute_all_feature_centroids()
  1277. {
  1278.     int x, y;
  1279.     Feature *feature;
  1280.  
  1281.     /* Only do this if features and a feature layer to work with. */
  1282.     if (featurelist == NULL)
  1283.       return;
  1284.     if (!features_defined())
  1285.       return;
  1286.     /* Clear out the features. */
  1287.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1288.     feature->size = 0;
  1289.     feature->x = feature->y = 0;
  1290.     }
  1291.     for_all_cells(x, y) {
  1292.     feature = feature_at(x, y);
  1293.     if (feature != NULL) {
  1294.         ++(feature->size);
  1295.         feature->x += x;  feature->y += y;
  1296.     }
  1297.     }
  1298.     for (feature = featurelist; feature != NULL; feature = feature->next) {
  1299.     if (feature->size > 0) {
  1300.         feature->x = feature->x / feature->size;
  1301.         feature->y = feature->y / feature->size;
  1302.     }
  1303.     }
  1304. }
  1305.  
  1306. void
  1307. compute_feature_centroid(feature)
  1308. Feature *feature;
  1309. {
  1310.     int x, y, fid;
  1311.  
  1312.     feature->size = 0;
  1313.     feature->x = feature->y = 0;
  1314.     for_all_cells(x, y) {
  1315.     fid = raw_feature_at(x, y);
  1316.     if (feature->id == fid) {
  1317.         feature->x += x;  feature->y += y;
  1318.     }
  1319.     }
  1320.     if (feature->size > 0) {
  1321.     feature->x = feature->x / feature->size;
  1322.     feature->y = feature->y / feature->size;
  1323.     }
  1324. }
  1325.  
  1326. int 
  1327. num_features()
  1328. {
  1329.     int f = 0, x, y;
  1330.  
  1331.     if (!features_defined())
  1332.       return 0;
  1333.  
  1334.     for_all_cells(x, y) {
  1335.     f = max(f, raw_feature_at(x, y));
  1336.     }
  1337.     return f;
  1338. }
  1339.  
  1340. /* Compute the coords of a point in the given direction. */
  1341.  
  1342. int
  1343. point_in_dir(x, y, dir, xp, yp)
  1344. int x, y, dir, *xp, *yp;
  1345. {
  1346.     *xp = wrapx(x + dirx[dir]);  *yp = y + diry[dir];
  1347.     return (in_area(*xp, *yp));
  1348. }
  1349.  
  1350. int
  1351. interior_point_in_dir(x, y, dir, xp, yp)
  1352. int x, y, dir, *xp, *yp;
  1353. {
  1354.     *xp = wrapx(x + dirx[dir]);  *yp = y + diry[dir];
  1355.     return (inside_area(*xp, *yp));
  1356. }
  1357.  
  1358. int
  1359. point_in_dir_n(x, y, dir, n, xp, yp)
  1360. int x, y, dir, n, *xp, *yp;
  1361. {
  1362.     *xp = wrapx(x + n * dirx[dir]);  *yp = y + n * diry[dir];
  1363.     return (in_area(*xp, *yp));
  1364. }
  1365.  
  1366. int
  1367. interior_point_in_dir_n(x, y, dir, n, xp, yp)
  1368. int x, y, dir, n, *xp, *yp;
  1369. {
  1370.     *xp = wrapx(x + n * dirx[dir]);  *yp = y + n * diry[dir];
  1371.     return (inside_area(*xp, *yp));
  1372. }
  1373.  
  1374. /* Return a random point guaranteed inside the area. */
  1375.  
  1376. int
  1377. random_point(xp, yp)
  1378. int *xp, *yp;
  1379. {
  1380.     int tries = 500;
  1381.  
  1382.     while (tries-- > 0) {
  1383.     *xp = xrandom(area.width);  *yp = xrandom(area.height - 2) + 1;
  1384.     if (inside_area(*xp, *yp))
  1385.       return TRUE;
  1386.     }
  1387.     return FALSE;
  1388. }
  1389.  
  1390. /* Return a random point guaranteed on the edge of the area. */
  1391.  
  1392. int
  1393. random_edge_point(xp, yp)
  1394. int *xp, *yp;
  1395. {
  1396.     int tries = 500, ratio, val;
  1397.  
  1398.     while (tries-- > 0) {
  1399.     if (area.xwrap) {
  1400.         *xp = xrandom(area.width);
  1401.         *yp = (flip_coin() ? 0 : area.height - 1);
  1402.     } else {
  1403.         ratio = ((area.width - area.halfheight) * 100) / (area.width + area.halfheight);
  1404.         if (probability(ratio)) {
  1405.         /* Pick along top or bottom edge. */
  1406.         if (flip_coin()) {
  1407.             *xp = xrandom(area.width - area.halfheight) + area.halfheight;
  1408.             *yp = 0;
  1409.         } else {
  1410.             *xp = xrandom(area.width - area.halfheight);
  1411.             *yp = area.height - 1;
  1412.         }
  1413.         } else {
  1414.         /* Pick along right or left side. */
  1415.         if (flip_coin()) {
  1416.             /* Pick along right side. */
  1417.             if (flip_coin()) {
  1418.             /* Pick along upper right side. */
  1419.             val = xrandom(area.halfheight);
  1420.             *xp = area.width - val;
  1421.             *yp = area.halfheight + val;
  1422.             } else {
  1423.             /* Pick along lower right side. */
  1424.             *xp = area.width;
  1425.             *yp = xrandom(area.halfheight);
  1426.             }
  1427.         } else {
  1428.             /* Pick along left side. */
  1429.             if (flip_coin()) {
  1430.             /* Pick along upper left side. */
  1431.             *xp = 0;
  1432.             *yp = area.halfheight + xrandom(area.halfheight);
  1433.             } else {
  1434.             /* Pick along lower left side. */
  1435.             val = xrandom(area.halfheight);
  1436.             *xp = val;
  1437.             *yp = area.halfheight - val;
  1438.             }
  1439.         }
  1440.         }
  1441.     }
  1442.     if (in_area(*xp, *yp) && !inside_area(*xp, *yp))
  1443.       return TRUE;
  1444.     }
  1445.     return FALSE;
  1446. }
  1447.  
  1448. /* Return a random point guaranteed to be within a given radius of
  1449.    a given point. */
  1450.  
  1451. int
  1452. random_point_near(cx, cy, radius, xp, yp)
  1453. int cx, cy, radius, *xp, *yp;
  1454. {
  1455.     int tries = 500;
  1456.  
  1457.     if (radius <= 0)
  1458.       return FALSE;
  1459.     while (tries-- > 0) {
  1460.     *xp = cx + xrandom(2 * radius + 1) - radius;
  1461.     *yp = cy + xrandom(2 * radius + 1) - radius;
  1462.     if (inside_area(*xp, *yp)
  1463.         && distance(cx, cy, *xp, *yp) <= radius)
  1464.           return TRUE;
  1465.     }
  1466.     return FALSE;
  1467. }
  1468.  
  1469. /* Return a random point guaranteed to be within a given radius of
  1470.    a given point. */
  1471.  
  1472. int
  1473. random_point_in_area(cx, cy, rx, ry, xp, yp)
  1474. int cx, cy, rx, ry, *xp, *yp;
  1475. {
  1476.     int tries = 500;
  1477.  
  1478.     while (tries-- > 0) {
  1479.     *xp = cx + xrandom(2 * rx + 1) - rx;
  1480.     *yp = cy + xrandom(2 * ry + 1) - ry;
  1481.     if (inside_area(*xp, *yp)
  1482.         && distance(cx, cy, *xp, *yp) <= max(rx - ry, ry - rx))
  1483.       return TRUE;  /* (should fix test?) */
  1484.     }
  1485.     return FALSE;
  1486. }
  1487.  
  1488. /* Generic warning that a terrain subtype is incorrect. */
  1489.  
  1490. void
  1491. terrain_subtype_warning(context, t)
  1492. char *context;
  1493. int t;
  1494. {
  1495.     run_warning("In %s: Garbage t%d (%s) subtype %d",
  1496.         context, t, t_type_name(t), t_subtype(t));
  1497. }
  1498.  
  1499. /* Given a vector, return the direction that best approximates it. */
  1500.  
  1501. int
  1502. approx_dir(dx, dy)
  1503. int dx, dy;
  1504. {
  1505.     if (dx == 0) {
  1506.     if (dy == 0)
  1507.       return -1; /* should flag so can use special cursor */
  1508.     if (dy > 0)
  1509.       return NORTHEAST;
  1510.     return SOUTHWEST;
  1511.     } else if (dx > 0) {
  1512.         /* Check for the axes first. */
  1513.     if (dy == 0)
  1514.       return EAST;
  1515.     if (dy == (-dx))
  1516.       return SOUTHEAST;
  1517.     if (dy > dx)
  1518.       return NORTHEAST;
  1519.     if ((-dy) <= dx / 2)
  1520.       return EAST;
  1521.     if ((-dy) < dx * 2)
  1522.       return SOUTHEAST;
  1523.     return SOUTHWEST;
  1524.     } else {
  1525.         /* Check for the axes first. */
  1526.     if (dy == 0)
  1527.       return WEST;
  1528.         if (dy == (-dx))
  1529.           return NORTHWEST;
  1530.     if (dy > (-dx) * 2)
  1531.       return NORTHEAST;
  1532.     if (dy >= (-dx) / 2)
  1533.       return NORTHWEST;
  1534.     if (dy > dx)
  1535.       return WEST;
  1536.     return SOUTHWEST;
  1537.     }
  1538. }
  1539.  
  1540. /* Computing distance in a hexagonal system is a little peculiar, since it's
  1541.    sometimes just delta x or y, and other times is the sum.  Basically there
  1542.    are six formulas to compute distance, depending on the direction between
  1543.    the two points.  If the area wraps, this routine reports the shortest
  1544.    distance. */
  1545.  
  1546. int
  1547. distance(x1, y1, x2, y2)
  1548. int x1, y1, x2, y2;
  1549. {
  1550.     int dx = x2 - x1, dy = y2 - y1;
  1551.  
  1552.     if (area.xwrap) {
  1553.         /* Choose the shortest way around a cylinder. */
  1554.         dx = (dx < 0 ? (dx < 0 - area.width / 2 ? area.width + dx : dx)
  1555.                  : (dx > area.width / 2 ? dx - area.width : dx));
  1556.     }
  1557.     if (dx >= 0) {
  1558.     if (dy >= 0) {
  1559.         return (dx + dy);
  1560.     } else if ((0 - dy) <= dx) {
  1561.         return dx;
  1562.     } else {
  1563.         return (0 - dy);
  1564.     }
  1565.     } else {
  1566.     if (dy <= 0) {
  1567.         return (0 - (dx + dy));
  1568.     } else if (dy <= (0 - dx)) {
  1569.         return (0 - dx);
  1570.     } else {
  1571.         return dy;
  1572.     }
  1573.     }
  1574. }
  1575.  
  1576. int
  1577. world_distance(x1, y1, x2, y2)
  1578. int x1, y1, x2, y2;
  1579. {
  1580.     int dx = x2 - x1, dy = y2 - y1;
  1581.  
  1582.     /* Choose the shortest way around the world. */
  1583.     dx = (dx < 0 ? (dx < 0 - world.circumference / 2 ? world.circumference + dx : dx)
  1584.              : (dx > world.circumference / 2 ? dx - world.circumference : dx));
  1585.     if (dx >= 0) {
  1586.     if (dy >= 0) {
  1587.         return (dx + dy);
  1588.     } else if ((0 - dy) <= dx) {
  1589.         return dx;
  1590.     } else {
  1591.         return (0 - dy);
  1592.     }
  1593.     } else {
  1594.     if (dy <= 0) {
  1595.         return (0 - (dx + dy));
  1596.     } else if (dy <= (0 - dx)) {
  1597.         return (0 - dx);
  1598.     } else {
  1599.         return dy;
  1600.     }
  1601.     }
  1602. }
  1603.  
  1604. /* Find the direction matching the given x and y, return -1 if no
  1605.    match.  Callers should be careful to test for this! */
  1606.  
  1607. int
  1608. closest_dir(x, y)
  1609. int x, y;
  1610. {
  1611.     int dir;
  1612.  
  1613.     for_all_directions(dir) {
  1614.     if (dirx[dir] == x && diry[dir] == y)
  1615.       return dir;
  1616.     }
  1617.     return -1;
  1618. }
  1619.  
  1620. /* should put date-handling code here? */
  1621.  
  1622. #ifdef DESIGNERS
  1623.  
  1624. /* Cell painting. */
  1625.  
  1626. static void
  1627. paint_cell_1(x, y)
  1628. int x, y;
  1629. {
  1630.     /* Only do anything if we're actually changing to a different type. */
  1631.     if (terrain_at(x, y) != tmpttype) {
  1632.     set_terrain_at(x, y, tmpttype);
  1633.     see_exact(tmpside, x, y);
  1634.     }
  1635. }
  1636.  
  1637. void
  1638. paint_cell(side, x, y, r, t)
  1639. Side *side;
  1640. int x, y, r, t;
  1641. {
  1642.     tmpside = side;
  1643.     tmpttype = t;
  1644.     apply_to_area_plus_edge(x, y, r, paint_cell_1);
  1645. }
  1646.  
  1647. void
  1648. paint_border(side, x, y, dir, t, mode)
  1649. Side *side;
  1650. int x, y, dir, t, mode;
  1651. {
  1652.     int oldbord;
  1653.  
  1654.     if (!inside_area(x, y))
  1655.       return;
  1656.     allocate_area_aux_terrain(t);
  1657.     oldbord = border_at(x, y, dir, t);
  1658.     set_border_at(x, y, dir, t, (mode < 0 ? !oldbord : mode));
  1659.     if (oldbord != border_at(x, y, dir, t)) {
  1660.         /* We do both a see_exact and update because see_exact doesn't
  1661.            account for linear terrain changes. */
  1662.     see_exact(side, x, y);
  1663.     update_cell_display(side, x, y, TRUE);
  1664.     see_exact(side, x+dirx[dir], y+diry[dir]);
  1665.     update_cell_display(side, x+dirx[dir], y+diry[dir], TRUE);
  1666.     }
  1667. }
  1668.  
  1669. void
  1670. paint_connection(side, x, y, dir, t, mode)
  1671. Side *side;
  1672. int x, y, dir, t, mode;
  1673. {
  1674.     int oldconn;
  1675.  
  1676.     if (!inside_area(x, y))
  1677.       return;
  1678.     allocate_area_aux_terrain(t);
  1679.     oldconn = connection_at(x, y, dir, t);
  1680.     set_connection_at(x, y, dir, t, (mode < 0 ? !oldconn : mode));
  1681.     if (oldconn != connection_at(x, y, dir, t)) {
  1682.         /* We do both a see_exact and update because see_exact doesn't
  1683.            account for linear terrain changes. */
  1684.     see_exact(side, x, y);
  1685.     update_cell_display(side, x, y, TRUE);
  1686.     see_exact(side, x+dirx[dir], y+diry[dir]);
  1687.     update_cell_display(side, x+dirx[dir], y+diry[dir], TRUE);
  1688.     }
  1689. }
  1690.  
  1691. /* Coating painting. */
  1692.  
  1693. static void
  1694. paint_coating_1(x, y)
  1695. int x, y;
  1696. {
  1697.     int olddepth = aux_terrain_at(x, y, tmpttype);
  1698.  
  1699.     if (olddepth != tmpint) {
  1700.     set_aux_terrain_at(x, y, tmpttype, tmpint);
  1701.     see_exact(tmpside, x, y);
  1702.     }
  1703. }
  1704.  
  1705. void
  1706. paint_coating(side, x, y, r, t, depth)
  1707. Side *side;
  1708. int x, y, r, t, depth;
  1709. {
  1710.     allocate_area_aux_terrain(t);
  1711.     tmpside = side;
  1712.     tmpttype = t;
  1713.     tmpint = depth;
  1714.     apply_to_area_plus_edge(x, y, r, paint_coating_1);
  1715. }
  1716.  
  1717. /* Painting of people sides. */
  1718.  
  1719. static void
  1720. paint_people_1(x, y)
  1721. int x, y;
  1722. {
  1723.     int oldpeop = people_side_at(x, y);
  1724.  
  1725.     if (oldpeop != tmpint) {
  1726.     set_people_side_at(x, y, tmpint);
  1727.     see_exact(tmpside, x, y);
  1728.     }
  1729. }
  1730.  
  1731. void
  1732. paint_people(side, x, y, r, s)
  1733. Side *side;
  1734. int x, y, r, s;
  1735. {
  1736.     allocate_area_people_sides();
  1737.     tmpside = side;
  1738.     tmpint = s;
  1739.     apply_to_area(x, y, r, paint_people_1);
  1740. }
  1741.  
  1742. /* Painting of geographical features. */
  1743.  
  1744. static void
  1745. paint_feature_1(x, y)
  1746. int x, y;
  1747. {
  1748.     int oldfid = raw_feature_at(x, y);
  1749.     Feature *oldfeature;
  1750.  
  1751.     if (oldfid != tmpint) {
  1752.     set_raw_feature_at(x, y, tmpint);
  1753.     ++(tmpfeature->size);
  1754.     see_exact(tmpside, x, y);
  1755.         if (oldfid != 0) {
  1756.         oldfeature = find_feature(oldfid);
  1757.         if (oldfeature != NULL)
  1758.           --(oldfeature->size);
  1759.     }
  1760.     }
  1761. }
  1762.  
  1763. void
  1764. paint_feature(side, x, y, r, f)
  1765. Side *side;
  1766. int x, y, r, f;
  1767. {
  1768.     Feature *newfeature;
  1769.  
  1770.     init_features();
  1771.     newfeature = find_feature(f);
  1772.     if (newfeature != NULL) {
  1773.     tmpside = side;
  1774.     tmpfeature = newfeature;
  1775.     tmpint = f;
  1776.     apply_to_area(x, y, r, paint_feature_1);
  1777.     }
  1778. }
  1779.  
  1780. /* Painting of terrain elevations. */
  1781.  
  1782. static void
  1783. paint_elev_1(x, y)
  1784. int x, y;
  1785. {
  1786.     int n, t = terrain_at(x, y), oldelev = elev_at(x, y);
  1787.  
  1788.     /* Clip desired elevation to what's allowed for the terrain here. */
  1789.     n = max(t_elev_min(t), min(tmpint, t_elev_max(t)));
  1790.     if (n != oldelev) {
  1791.     set_elev_at(x, y, n);
  1792.     see_exact(tmpside, x, y);
  1793.     }
  1794. }
  1795.  
  1796. void
  1797. paint_elevation(side, x, y, r, elev)
  1798. Side *side;
  1799. int x, y, r, elev;
  1800. {
  1801.     allocate_area_elevations();
  1802.     tmpside = side;
  1803.     tmpint = elev;
  1804.     apply_to_area_plus_edge(x, y, r, paint_elev_1);
  1805. }
  1806.  
  1807. static void
  1808. paint_temp_1(x, y)
  1809. int x, y;
  1810. {
  1811.     int n, t = terrain_at(x, y), oldtemp = temperature_at(x, y);
  1812.     
  1813.     n = max(t_temp_min(t), min(tmpint, t_temp_max(t)));
  1814.     if (n != oldtemp) {
  1815.     set_temperature_at(x, y, n);
  1816.     see_exact(tmpside, x, y);
  1817.     }
  1818. }
  1819.  
  1820. void
  1821. paint_temperature(side, x, y, r, temp)
  1822. Side *side;
  1823. int x, y, r, temp;
  1824. {
  1825.     allocate_area_temperatures();
  1826.     tmpside = side;
  1827.     tmpint = temp;
  1828.     apply_to_area_plus_edge(x, y, r, paint_temp_1);
  1829. }
  1830.  
  1831. static void
  1832. paint_material_1(x, y)
  1833. int x, y;
  1834. {
  1835.     int oldm = material_at(x, y, tmpmtype);
  1836.  
  1837.     if (oldm != tmpint) {
  1838.     set_material_at(x, y, tmpmtype, tmpint);
  1839.     see_exact(tmpside, x, y);
  1840.     }
  1841. }
  1842.  
  1843. void
  1844. paint_material(side, x, y, r, m, amt)
  1845. Side *side;
  1846. int x, y, r, m, amt;
  1847. {
  1848.     allocate_area_material(m);
  1849.     tmpside = side;
  1850.     tmpmtype = m;
  1851.     tmpint = amt;
  1852.     apply_to_area_plus_edge(x, y, r, paint_material_1);
  1853. }
  1854.  
  1855. /* Cloud painting is more complicated because up to three separate
  1856.    layers are involved. */
  1857.  
  1858. static void
  1859. paint_clouds_1(x, y)
  1860. int x, y;
  1861. {
  1862.     int oldcl = raw_cloud_at(x, y);
  1863.     int oldbot = raw_cloud_bottom_at(x, y);
  1864.     int oldhgt = raw_cloud_height_at(x, y);
  1865.     int changed = FALSE;
  1866.  
  1867.     if (oldcl != tmpint) {
  1868.     set_raw_cloud_at(x, y, tmpint);
  1869.     changed = TRUE;
  1870.     }
  1871.     if (oldbot != tmpint2) {
  1872.     set_raw_cloud_bottom_at(x, y, tmpint2);
  1873.     changed = TRUE;
  1874.     }
  1875.     if (oldhgt != tmpint3) {
  1876.     set_raw_cloud_height_at(x, y, tmpint3);
  1877.     changed = TRUE;
  1878.     }
  1879.     if (changed)
  1880.       see_exact(tmpside, x, y);
  1881. }
  1882.  
  1883. void
  1884. paint_clouds(side, x, y, r, cloudtype, bot, hgt)
  1885. Side *side;
  1886. int x, y, r, cloudtype, bot, hgt;
  1887. {
  1888.     allocate_area_clouds();
  1889.     /* (should not always do altitudes) */
  1890.     allocate_area_cloud_altitudes();
  1891.     tmpside = side;
  1892.     tmpint = cloudtype;
  1893.     tmpint2 = bot;
  1894.     tmpint3 = hgt;
  1895.     apply_to_area_plus_edge(x, y, r, paint_clouds_1);
  1896. }
  1897.  
  1898. static void
  1899. paint_winds_1(x, y)
  1900. int x, y;
  1901. {
  1902.     int oldw = raw_wind_at(x, y);
  1903.  
  1904.     if (oldw != tmpint) {
  1905.     set_raw_wind_at(x, y, tmpint);
  1906.     see_exact(tmpside, x, y);
  1907.     }
  1908. }
  1909.  
  1910. void
  1911. paint_winds(side, x, y, r, dir, force)
  1912. Side *side;
  1913. int x, y, r, dir, force;
  1914. {
  1915.     allocate_area_winds();
  1916.     tmpside = side;
  1917.     tmpint = force << 3 | dir;
  1918.     apply_to_area_plus_edge(x, y, r, paint_winds_1);
  1919. }
  1920.  
  1921. #endif /* DESIGNERS */
  1922.