home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Games / Bolo 0.99.6 / More information / Sample Code / Std Autopilot / Standard Autopilot.c < prev    next >
Encoding:
Text File  |  1995-05-13  |  66.4 KB  |  1,899 lines  |  [TEXT/KAHL]

  1. // ****************************************************************************
  2. //
  3. // Bolo standard Autopilot Brain
  4. // (C) 1993-1995 Stuart Cheshire <cheshire@cs.stanford.edu>
  5. // I make no claims that this is good code. It is provided solely as
  6. // simple example code to assist in writing Bolo plug-in Brain modules.
  7. // I do not have the time to tidy it up and make it elegant at all.
  8. // It's poorly structured and it uses far too many global variables.
  9. //
  10. // Version history:
  11. // 0.9 12th May 1995. Updated to new version 3 Brain interface.
  12. //     Made it prefer building slightly ahead, rather than under the tank,
  13. //     when moving at a reasonable speed (speeds >= forest speed)
  14. // 0.8 22nd Nove 1993. Added "Do Building" menu option, and moved
  15. //     decide_building(nearx, neary) call to inside "if (correction…" statement
  16. // 0.7 6th Nov 1993. Converted to A-Star heuristic, added route algorithm
  17. //     debugging window and made tanks seek out boats for transportation.
  18. //     Record time for Everard Island 18 min 30 secs
  19. // 0.6 19th Oct 1993. Made it not try to pick up pillboxes which are sitting in deep sea.
  20. // 0.5 13th Oct 1993. Major improvements to route finding and decision making. Pillbox
  21. //     firing areas used, clear path routines, revised progress/boredom routines.
  22. // 0.4 7th Oct 1993. Route finding switched to multi-parameter decision.
  23. // 0.3 1st Oct 1993. New menu options, including "assassin" mode.
  24. // 0.2 26th May 1993. Released with Bolo 0.99.
  25. // 0.1 21st Feb 1993. Built into Bolo 0.98 as "Autopilot"
  26.  
  27. #define AUTO_DEBUG 0
  28.  
  29. // ****************************************************************************
  30.  
  31. // Define an integer square root routine
  32. #include <FixMath.h>
  33. #define sqrt(X) (FracSqrt(X) >> 15)
  34.  
  35. // ****************************************************************************
  36.  
  37. #include "vsprintf.h"
  38. #include "Brain.h"
  39.  
  40. // ****************************************************************************
  41.  
  42. #define abs(X) (((X) < 0 ) ? -(X) : (X))
  43. #define max(X,Y) ((X) > (Y) ? (X) : (Y))
  44. #define min(X,Y) ((X) < (Y) ? (X) : (Y))
  45.  
  46. // pillpickup_x and y are used to record the location of the last
  47. // pillbox picked up in case it turns out to be fatal deep sea underneath
  48.  
  49. local const BrainInfo *info;
  50. local long TimeNow;
  51. local MAP_X nearx, pillpickup_x, fatal_x;
  52. local MAP_Y neary, pillpickup_y, fatal_y;
  53. local MAP_X tankleftx, tankrightx;
  54. local MAP_Y tanktopy, tankbottomy;
  55. local Boolean tank_close_to_mine;
  56. local Boolean still_on_boat;    // Set until tank gets off boat
  57. local BYTE land_direction;        // Initial guess at where the land is
  58.  
  59. // If cannot reach a target, get bored and ignore it after 20 seconds
  60. #define ATTENTION_SPAN (60*20)
  61. #define MAX_VIS_RANGE 0x7FFF
  62. #define DEFENSIVE_RANGE 0xA00
  63.  
  64. typedef struct
  65.     {
  66.     u_long remaining_progress;    // Current 'best' point so far
  67.     long last_progress;            // Last time progress was made
  68.     long ignore_until;            // when we are bored with something
  69.     } ProgressInfo;
  70. #define MAX_PROGRESS 0xFFFFFFFF
  71. local long boredomtime = ATTENTION_SPAN;
  72. local ProgressInfo *tankprogress, *pillprogress, *baseprogress;
  73. local ProgressInfo scoutingprogress, manrescueprogress;
  74. //local u_long previous_closest_dist = MAX_VIS_RANGE;
  75. //local long current_attempt_time;
  76.  
  77. // Can place pillbox on swamp, crater, road, rubble and grass
  78. static Boolean can_build_pillbox[NUM_TERRAINS] = { 0,0,1,1, 1,0,1,1, 0,0,0,0, 0,0 };
  79.  
  80. // Keyboard Control variables
  81. local u_long keys, taps, last_keys, last_taps;
  82.  
  83. // Menu handling variables and mode settings
  84. #define MyMenuID 1000
  85. local MenuHandle MyMenu;
  86. local WindowPtr debugwindow, routewindow;
  87.  
  88. local Boolean do_explain   = AUTO_DEBUG;
  89. local Boolean do_showroute = AUTO_DEBUG;
  90.  
  91. enum
  92.     {
  93.     m_about = 1,
  94.     m_sep1, m_default, m_assassin, m_pillhunter, m_basehunter, m_defensive,
  95.     m_sep2, m_explore, m_laymines, m_clearmines, m_dobuilding,
  96.     m_attacktanks, m_attackpills, m_attackbases, m_repairpills, m_placepills, m_ppoffensive,
  97.     m_sep3, m_explain, m_route
  98.     };
  99.  
  100. typedef struct
  101.     {
  102.     Boolean explore, laymines, clearmines, dobuilding;
  103.     Boolean attacktanks, attackpills, attackbases, repairpills, placepills, ppoffensive;
  104.     } SETTINGS;
  105.  
  106. // Flags are:                         ex lm cm db at ap cb rp pp po
  107. local const SETTINGS s_default    = { 1, 0, 1, 1, 1, 1, 1, 1, 1, 0 };
  108. local const SETTINGS s_assassin   = { 1, 0, 1, 1, 1, 0, 0, 1, 1, 1 };
  109. local const SETTINGS s_defensive  = { 0, 0, 1, 1, 1, 1, 0, 1, 1, 0 };
  110. local const SETTINGS s_pillhunter = { 1, 0, 1, 1, 0, 1, 0, 1, 1, 0 };
  111. local const SETTINGS s_basehunter = { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0 };
  112. local SETTINGS s;
  113.  
  114. // Thinking variables
  115. local Boolean shootit, shootsoon, runaway;
  116. #define SHOOT_NOTHING 0xFFFF
  117. local OBJECT shootwhat;
  118. local Boolean *shoot_path_costs;
  119. local BYTE chosen_gunrange;        // Desired gun range, for shooting mines
  120. local BYTE shoot_direction;        // to aim the gun accurately
  121. local BYTE shoot_dir_vote;        // shoot_direction converted to range 0-15
  122. local BYTE chosen_direction;
  123. local BYTE flying_shells;        // total number of shells in flight at the moment
  124. local BYTE incoming_shells;        // total number of shells heading towards us
  125. local long direction_votes[16];
  126. local u_long target_distances[16];
  127. local BYTE direction_maxspeeds[16];
  128.  
  129. local MAP_X scoutx;
  130. local MAP_Y scouty;
  131. #define CAN_DO_BUILDING (info->build->action == 0 && info->man_status == 0 && \
  132.                         !info->inboat && flying_shells == 0)
  133. #define CAN_BUILD_PILLBOX (CAN_DO_BUILDING && \
  134.                         s.placepills && info->carriedpills && info->trees >= 4)
  135.  
  136. typedef struct { char x; char y; } charpair;
  137.  
  138. typedef union
  139.     {
  140.     charpair s25[25];
  141.     struct { charpair s1[1]; charpair s8[8]; charpair s16[16]; } s;
  142.     } SURROUNDING_SQUARES;
  143.  
  144. local const SURROUNDING_SQUARES surrounding =
  145.     {
  146.     0,0,
  147.     0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0, -1,-1,
  148.     0,-2, 1,-2, 2,-2, 2,-1, 2,0, 2,1, 2,2, 1,2,
  149.     0,2, -1,2, -2,2, -2,1, -2,0, -2,-1, -2,-2, -1, -2
  150.     };
  151.  
  152. // ****************************************************************************
  153.  
  154. // Debugging message routines
  155.  
  156. #define EXPLAIN_WITH_MESSAGES 0
  157.  
  158. local void sendmessage(u_char *msg)
  159.     {
  160.     int i;    // Setting player bits to all zero makes this a debugger message
  161.     for (i=0; i<(info->max_players+31)/32; i++) info->messagedest[i] = 0;
  162.     for (i=0; i<=msg[0]; i++) info->sendmessage[i] = msg[i];
  163.     }
  164.  
  165. local void debug(char *format, ...)
  166.     {
  167.     unsigned char buffer[256];
  168.     va_list ptr;
  169.     va_start(ptr,format);
  170.     buffer[0] = vsprintf((char *)buffer+1, format, ptr);
  171.     va_end(ptr);
  172.     DebugStr(buffer);
  173.     }
  174.  
  175. local Boolean SameString(const unsigned char *a, const unsigned char *b)
  176.     {
  177.     int i;
  178.     for (i=0; i<=a[0]; i++) if (a[i] != b[i]) return(FALSE);
  179.     return(TRUE);
  180.     }
  181.  
  182. local void explain(char *format, ...)
  183.     {
  184.     if (do_explain)
  185.         {
  186.         static unsigned char old_buffer[256];
  187.         unsigned char buffer[256];
  188.         va_list ptr;
  189.         va_start(ptr,format);
  190.         buffer[0] = vsprintf((char *)buffer+1, format, ptr);
  191.         va_end(ptr);
  192.         
  193. #if EXPLAIN_WITH_MESSAGES
  194.         if (info->sendmessage[0] == 0 && !SameString(buffer, old_buffer))
  195.             { sendmessage(buffer); BlockMove(buffer, old_buffer, 1+buffer[0]); }
  196. #else
  197.         if (!SameString(buffer, old_buffer))
  198.             {
  199.             GrafPtr old;
  200.             RgnHandle updateRgn = NewRgn();
  201.             GetPort(&old);
  202.             SetPort(debugwindow);
  203.             TextFont(geneva);
  204.             TextSize(10);
  205.             ScrollRect(&debugwindow->portRect, 0, -12, updateRgn);
  206.             DisposeRgn(updateRgn);
  207.             MoveTo(debugwindow->portRect.left + 6, debugwindow->portRect.bottom - 6);
  208.             DrawString(buffer);
  209.             SetPort(old);
  210.             BlockMove(buffer, old_buffer, 1+buffer[0]);
  211.             }
  212. #endif
  213.         }
  214.     }
  215.  
  216. // ****************************************************************************
  217.  
  218. // General utility routines
  219.  
  220. local TERRAIN raw_getmapcell(MAP_X x, MAP_Y y)
  221.     {
  222.     // This was the old way, when Brains were just given a small square of the map
  223. /*    if (x < info->view_left || y < info->view_top) return(DEEPSEA);*/
  224. /*    y -= info->view_top;*/
  225. /*    x -= info->view_left;*/
  226. /*    if (x >= info->view_width || y >= info->view_height) return(DEEPSEA);*/
  227. /*    return(info->viewdata[y*info->view_width + x]);*/
  228.  
  229.     // This is the new way, now that Brains get a pointer to the whole world
  230.     return(info->theWorld[(u_short)y << 8 | x]);
  231.     }
  232.  
  233. // These two read the terrain / check for mine at MAP coordinates X,Y
  234. #define getmapcellM(X,Y) (raw_getmapcell((X),(Y)) & TERRAIN_MASK)
  235. #define checkmineM(X,Y)  (raw_getmapcell((X),(Y)) & TERRAIN_MINE)
  236.  
  237. // These two read the terrain / check for mine at WORLD coordinates X,Y
  238. #define getmapcellW(X,Y) getmapcellM((X)>>8, (Y)>>8)
  239. #define checkmineW(X,Y)  checkmineM((X)>>8, (Y)>>8)
  240.  
  241. local u_long findrange(WORLD_X x1, WORLD_Y y1, WORLD_X x2, WORLD_Y y2)
  242.     {
  243.     register long xdiff = (long)x1 - (long)x2;
  244.     register long ydiff = (long)y1 - (long)y2;
  245.     return(sqrt(xdiff*xdiff + ydiff*ydiff));
  246.     }
  247.  
  248. #define objectrange_to_me(OB) findrange((OB)->x, (OB)->y, info->tankx, info->tanky)
  249.  
  250. // For Mac fixed point trig routines, full circle is 2 * PI * 0x10000
  251. // We want full circle to be 0x100, so divide by (2 * PI * 0x10000 / 0x100)
  252. // which is 1608 in decimal
  253. #define aim(X,Y) ((FixATan2(-(Y),(X))/1608) & 0xFF)
  254.  
  255. // sin and cos routines are adjusted to take angles in the range 0-255
  256. // and return return values in the range +/-128
  257. #define sin(X) ((short)(FracSin((u_char)(X)*1608L) >> 23))
  258. #define cos(X) ((short)(FracCos((u_char)(X)*1608L) >> 23))
  259.  
  260. local ObjectInfo *find_object(OBJECT obtype, MAP_X x, MAP_Y y)
  261.     {
  262.     ObjectInfo *ob;
  263.     WORLD_X wx = (WORLD_X)x << 8;
  264.     WORLD_Y wy = (WORLD_Y)y << 8;
  265.     for (ob=&info->objects[0]; ob<&info->objects[info->num_objects]; ob++)
  266.         if (ob->object == obtype && ob->x == wx && ob->y == wy) return(ob);
  267.     return(NULL);
  268.     }
  269.  
  270. // ****************************************************************************
  271.  
  272. // Shots can't pass through buildings, half buildings or pillboxes
  273. // If we are chasing tank, also discourage wasting shots shooting forest
  274. // Men cannot run through buildings, half buildings, pillboxes, refbases or water/deepsea
  275. local BYTE stationary_target_path[NUM_TERRAINS] = { 5,  0,  0,  0,  0,  1,  0,  0,  4,  0,  0,  0, 16, 99 };
  276. local BYTE moving_target_path    [NUM_TERRAINS] = { 5,  0,  0,  0,  0,  4,  0,  0,  4,  0,  0,  0, 16, 99 };
  277. local BYTE running_man_path      [NUM_TERRAINS] = { 99, 99, 4,  4,  1,  2,  4,  1, 99,  1, 99, 99, 99, 99 };
  278.  
  279. // returns zero if there is a clear straight line path, from x,y, across terrain
  280. // specified by terraincosts, to the target at tx,ty, in at most maxsteps steps
  281. // (a step is half a map square)
  282. // If there is not a clear path, then it returns the cost,
  283. // measured in shots for shooting paths, and in time for man paths
  284. local short path_cost(WORLD_X x, WORLD_Y y, Boolean *terraincosts,
  285.     WORLD_X tx, WORLD_Y ty, WORD maxsteps)
  286.     {
  287.     BYTE direction = aim(tx - (long)x, ty - (long)y);
  288.     MAP_X lastx = 0, targx = tx>>8;
  289.     MAP_Y lasty = 0, targy = ty>>8;
  290.     short steps = findrange(tx, ty, x, y) >> 7;    // count in half-square steps
  291.     //short closest_step = 0;
  292.     short cost = 0;
  293.     if (steps > maxsteps) return(0x7FFF);
  294.  
  295.     // This first step is to make sure we skip over the initial square,
  296.     // and don't count a cost for it
  297.     x += sin(direction);
  298.     y -= cos(direction);
  299.  
  300.     while (--steps > 0)
  301.         {
  302.         x += sin(direction);
  303.         y -= cos(direction);
  304.         if ((x>>8)==targx && (y>>8)==targy) break;        // OK, reached target
  305.         if ((x>>8)==lastx && (y>>8)==lasty) continue;    // same square as last time -- skip it
  306.         cost += terraincosts[getmapcellW(x,y)];
  307.         }
  308.     return(cost);
  309.     }
  310.  
  311. // Man will not run over more than 5 squares of rubble, or 20 squares of road
  312. #define MAN_PATH(X,Y) (path_cost(info->tankx,info->tanky,running_man_path,(X),(Y),0x7FFF) < 20)
  313.  
  314. // Note, must assume shots CAN travel over unknown terrain, otherwise,
  315. // as soon as we leave the vicinity of an unsafe base, its terrain becomes
  316. // unknown, and we would immediately return, assuming it safe 
  317. local Boolean safe_base(ObjectInfo *base)
  318.     {
  319.     ObjectInfo *ob;
  320.     for (ob=&info->objects[0]; ob<&info->objects[info->num_objects]; ob++)
  321.         if (ob->object == OBJECT_PILLBOX && ob->pillbox_strength > 0 && (ob->info & OBJECT_HOSTILE))
  322.             if (path_cost(ob->x, ob->y, stationary_target_path, base->x, base->y, 16) == 0)
  323.                 return(FALSE);
  324.     return(TRUE);
  325.     }
  326.  
  327. // ****************************************************************************
  328.  
  329. // Route finding routines
  330.  
  331. #define ARMOUR_UNIT_COST 8    // The armour cost scale counts eighths of a unit of tank armour
  332. #define MAX_TIME_COST   0xFFFF
  333. #define MAX_SHELL_COST  0xFF
  334. #define MAX_ARMOUR_COST 0xFF
  335. #define UNKNOWN_COST    0xFFFF
  336. #define MAX_COST (UNKNOWN_COST-1)
  337.  
  338. // Notes:
  339. // The 'squarecost' array holds the costs to reach the target from the given square --
  340. // it forms a field for the tank to follow the steepest gradient downhill to its target.
  341. // The 'cost' values in the CostPoints are this cost to reach the destination, PLUS
  342. // a (mostly) conservative heuristic estimating the minimum cost for the tank to get
  343. // to this square from its current position. This heuristic helps guide the search
  344. // preferentially towards where the tank is now, rather then in fruitless directions
  345. // away from it.
  346.  
  347. typedef struct            // Used to find best route through cost array
  348.     {
  349.     u_char x;            // Location in array (NOT in MAP coordinates)
  350.     u_char y;
  351.     u_short time;        // Time to reach destination from this square
  352.     u_char shells;        // Shells required to reach destination from this square
  353.     u_char armour;        // Armour required to reach destination from this square (scaled)
  354.     u_char trees;
  355.     u_char spare;
  356.     u_char water;        // number of squares to be spent crossing water
  357.     u_char deepsea;        // set if path will cross deep sea
  358.     u_short cost;        // Overall 'cost' estimate to reach destination via this square
  359.     } CostPoint;
  360.  
  361. #define COST_SEARCH_RANGE 14
  362. // Tank can see the square it is on, and up to COST_SEARCH_RANGE
  363. // above, below and to either side of it
  364.  
  365. #define COST_ARRAY_SIZE (COST_SEARCH_RANGE + 1 + COST_SEARCH_RANGE)
  366. #define IN_COSTARRAY(X) ((BYTE)(X) < (BYTE)(COST_ARRAY_SIZE))
  367.  
  368. typedef u_char     u_char32   [32];                // Row of 32 unsigned char values
  369. typedef u_short    u_short32  [32];                // Row of 32 unsigned short values
  370.  
  371. local u_char32  pillcoverage[COST_ARRAY_SIZE];    // Array of rows of pillbox fire coverage
  372. local u_short32 squarecost  [COST_ARRAY_SIZE];    // Array of rows of cost values
  373. local u_short32 CPCost      [COST_ARRAY_SIZE];
  374.  
  375. local long costarray_time;        // time array was created
  376. // position of array on map, position of target on map, and
  377. // subtarget (target, or closest point if target is outside costarray)
  378. local MAP_X costarray_left, costtarget_x, subtarget_x;
  379. local MAP_Y costarray_top,  costtarget_y, subtarget_y;
  380. local BYTE costarray_boat;        // Whether costarray calculated for boat or tank
  381. local OBJECT costarray_targ;
  382. local u_char costarray_tankhits;
  383. // How many pillbox hits the tank's current position scores. Normally a two-hit square
  384. // is bad news, but if we are already sitting on a three-hit square, then two suddenly
  385. // looks quite desirable
  386. local BYTE ca_tankx, ca_tanky;    // Position of tank in costarray coordinates
  387.  
  388. #define MAX_HEAP_SIZE 200
  389. local CostPoint cost_heap[MAX_HEAP_SIZE];    // Sorted heap of CostPoints
  390. local short heap_size=0;
  391.  
  392. local void showroute(CostPoint c, u_short colour, u_short shotpoint)
  393.     {
  394.     RGBColor col = { 0, 0, 0 };
  395.     Rect r;
  396.     u_short lowbits = (colour & 0x7F) * 0x180 + 0x4000;
  397.     if (colour + 0x80 & 0x080) col.red   = lowbits;
  398.     if (colour + 0x80 & 0x100) col.green = lowbits;
  399.     if (colour + 0x80 & 0x200) col.blue  = lowbits;
  400.     RGBForeColor(&col);
  401.     r.top    = c.y * 8;
  402.     r.left   = c.x * 8;
  403.     r.bottom = r.top  + 8;
  404.     r.right  = r.left + 8;
  405.     if (shotpoint) InsetRect(&r, 1, 1);
  406.     PaintRect(&r);
  407.     //debug("%d,%d Cost %X Realcost %X", c.x, c.y, c.cost, colour);
  408.     }
  409.  
  410. local void addtoheap(int place, CostPoint new)
  411.     {
  412.     int parent = (place-1)>>1;
  413.     cost_heap[place]=new;
  414.     while (place>0 && cost_heap[parent].cost > cost_heap[place].cost)
  415.         {
  416.         CostPoint temp    = cost_heap[place ];
  417.         cost_heap[place ] = cost_heap[parent];
  418.         cost_heap[parent] = temp;
  419.         place=parent;
  420.         parent=(place-1)>>1;
  421.         }
  422.     }
  423.  
  424. local CostPoint removefromheap(void)
  425.     {
  426.     CostPoint top = cost_heap[0];            // extract top element
  427.     int gap   = 0;                            // top is now empty
  428.     int left  = 1;                            // Left child is element 1
  429.     int right = 2;                            // Right child is element 2
  430.     heap_size--;                            // We have removed one element
  431.     while(left<=heap_size)                    // move gap to bottom
  432.         {
  433.         if(right>heap_size || cost_heap[right].cost > cost_heap[left].cost)
  434.             { cost_heap[gap]=cost_heap[left ]; gap=left;  }
  435.         else{ cost_heap[gap]=cost_heap[right]; gap=right; }
  436.         left  = (gap<<1)+1;
  437.         right = (gap<<1)+2;
  438.         }
  439.     if(gap != heap_size) addtoheap(gap,cost_heap[heap_size]);
  440.     return(top);                            // return extracted element
  441.     }
  442.  
  443. // Note: the cost in the CostPoint is biased with the search heuristic
  444. // realcost is the actual cost to reach the destination from this point
  445. local void setcost(CostPoint c, u_short realcost)
  446.     {
  447.     int i;
  448.     Boolean already_present = (CPCost[c.y][c.x] < UNKNOWN_COST);
  449.     CPCost[c.y][c.x]     = c.cost;
  450.     squarecost[c.y][c.x] = realcost;
  451.  
  452.     // If adding a maxcost (which by definition cannot already be present
  453.     // because there is no pre-existing cost > MAX_COST) then don't bother
  454.     // putting it onto the heap (no point -- it cannot lead anywhere)
  455.     if (c.cost == MAX_COST) return;
  456.  
  457.     // If already present, try to find and replace the element in place in the heap
  458.     if (already_present)
  459.         for (i=0; i<heap_size; i++)
  460.             if (cost_heap[i].x == c.x && cost_heap[i].y == c.y)
  461.                 { addtoheap(i, c); return; }
  462.  
  463.     // If heap already full nuke last element (shouldn't happen too often)
  464.     if (heap_size >= MAX_HEAP_SIZE) heap_size--;
  465.     addtoheap(heap_size++, c);
  466.     }
  467.  
  468. local u_short route_square_time_costs[NUM_TERRAINS] =
  469.     {
  470.     10, 1, 8, 8,    // BUILDING, RIVER, SWAMP, CRATER
  471.      1, 3, 8, 2,    // ROAD, FOREST, RUBBLE, GRASS,
  472.      4, 1, 1, 1,    // HALFBUILDING, BOAT, DEEPSEA, REFBASE_T
  473.     1000, 1000        // PILLBOX_T, TERRAIN_UNKNOWN
  474.     };
  475.  
  476. // examine square in CostPoint c. The cost parameters have already been
  477. // seeded up to this point -- the current square remains to be added.
  478. local void examine(CostPoint c)
  479.     {
  480.     if (IN_COSTARRAY(c.x) && IN_COSTARRAY(c.y))
  481.         {
  482.         //Boolean examining_tanksquare = (c.x == ca_tankx && c.y == ca_tanky);
  483.         MAP_X x = costarray_left + c.x;
  484.         MAP_Y y = costarray_top  + c.y;
  485.         u_long dx = abs((long)x-(long)nearx);
  486.         u_long dy = abs((long)y-(long)neary);
  487.         u_long cpcost, heuristic = max(dx,dy) + min(dx,dy) / 2;
  488.         TERRAIN raw = raw_getmapcell(x,y);
  489.         TERRAIN t   = raw & TERRAIN_MASK;
  490.         short tankshells = info->shells;
  491.         short tankarmour = info->armour * ARMOUR_UNIT_COST;
  492.         short hits       = pillcoverage[c.y][c.x];
  493.         long  new_timecost   = c.time + route_square_time_costs[t];
  494.         short new_shellcost  = c.shells;
  495.         short new_armourcost = c.armour;
  496.         long newcost = 0;
  497.         Boolean count_cost = TRUE;
  498.         
  499.         // The following part of the cost evaluation is skipped if we are:
  500.         // (1) shooting something, and
  501.         // (2) this is a not boat costarray or this square is not water, and
  502.         // (3) this square has a clear path to the target
  503.         // because once we have a vantage point to shoot
  504.         // from, the cost of going further is irrelevant
  505.         if (costarray_targ != SHOOT_NOTHING && (!costarray_boat || !is_wet(t)))
  506.             {
  507.             long cost = path_cost((WORLD_X)x<<8,(WORLD_Y)y<<8,shoot_path_costs,
  508.                                     (WORLD_X)costtarget_x<<8,(WORLD_Y)costtarget_y<<8,15);
  509.             if (cost == 0 || c.shells + 2 * cost < info->shells) count_cost = FALSE;
  510.             }
  511.         if (count_cost)
  512.             {
  513.             new_armourcost += route_square_time_costs[t] * (hits - costarray_tankhits);
  514.             if (new_armourcost < 0) new_armourcost = 0;
  515.             
  516.             if (t == DEEPSEA) c.deepsea = TRUE;
  517.             else if (t == RIVER) c.water++;
  518.             else if (t == BUILDING)
  519.                 {
  520.                 if (tankshells < new_shellcost+8) newcost = MAX_COST;
  521.                 else new_shellcost += 5;
  522.                 }
  523.             else if (t == HALFBUILDING)
  524.                 {
  525.                 if (tankshells < new_shellcost+4) newcost = MAX_COST;
  526.                 else new_shellcost += 4;
  527.                 }
  528.             else if (t == REFBASE_T)
  529.                 {
  530.                 ObjectInfo *ob = find_object(OBJECT_REFBASE,x,y);
  531.                 if (ob && ob->info & OBJECT_HOSTILE) newcost = MAX_COST;
  532.                 }
  533.         
  534.             if (raw & TERRAIN_MINE)
  535.                 {
  536.                 // If clearing mines and we have enough shells free,
  537.                 // count some time and one shell, else count one armour hit
  538.                 if (s.clearmines && tankshells > new_shellcost + 4)
  539.                     { new_timecost += 8; new_shellcost++; }
  540.                 else new_armourcost += 3 * ARMOUR_UNIT_COST;
  541.                 }
  542.             
  543.             // Note: subtle stuff here. The 'cost' of water is carried unresolved,
  544.             // like a quantum superposition of two different states, until the search
  545.             // passes back onto land, where the cost is determined depending on whether
  546.             // the path from the land is via a boat or not, like a quantum wave collapse.
  547.             // The wave collapse can also be caused by the tank getting shot.
  548.             // If the tank is already in water, then we pretend it is on a little square
  549.             // of land, in order to precipitate that wave collapse and get the right answer
  550.             if (c.x == ca_tankx && c.y == ca_tanky && !costarray_boat) t = ROAD;
  551.             if (t==BOAT) c.water = c.deepsea = 0;            // on boat at this point, no cost
  552.             else if (hits || (t != RIVER && t != DEEPSEA))    // no boat, so count cost
  553.                 {
  554.                 if (c.deepsea) newcost = MAX_COST;
  555.                 else { new_timecost += 7 * c.water; new_shellcost += 6 * c.water; }
  556.                 c.water = c.deepsea = 0;    // tentative cost now paid, so zero counters
  557.                 }
  558.             }
  559.         //else debug("%d, %d can shoot %d, %d", x, y, costtarget_x, costtarget_y);
  560.         
  561.         if (new_timecost   > MAX_TIME_COST)   new_timecost   = MAX_TIME_COST;
  562.         if (new_shellcost  > MAX_SHELL_COST)  new_shellcost  = MAX_SHELL_COST;
  563.         if (new_armourcost > MAX_ARMOUR_COST) new_armourcost = MAX_ARMOUR_COST;
  564.     
  565.         // If this route consumes more armour than we have, then it is unreachable
  566.         if (tankarmour < new_armourcost) newcost = MAX_COST;
  567.         
  568.         // if newcost has not already been set to MAX_COST (ie impossible) then calculate it
  569.         if (newcost < MAX_COST)
  570.             {
  571.             // Make sure we don't divide by zero
  572.             if (tankshells > new_shellcost ) tankshells -= new_shellcost;  else tankshells = 1;
  573.             if (tankarmour > new_armourcost) tankarmour -= new_armourcost; else tankarmour = 1;
  574.             newcost = new_timecost + 100/tankshells + 200/tankarmour;
  575.             if (newcost > MAX_COST) newcost = MAX_COST;
  576.             }
  577.         
  578.         cpcost = newcost + heuristic;
  579.         if (cpcost > MAX_COST) cpcost = MAX_COST;
  580.  
  581.         if (CPCost[c.y][c.x] > cpcost)    
  582.             {
  583.             c.time   = new_timecost;
  584.             c.shells = new_shellcost;
  585.             c.armour = new_armourcost;
  586.             c.cost   = cpcost;
  587.             
  588.             // If we are not calculating a boat costarray, then the cost field generated
  589.             // should include the water costs so that the tank is guided in the right
  590.             // direction (which is NOT necessarily the same direction the search is taking).
  591.             if (newcost < MAX_COST && !costarray_boat)
  592.                 {
  593.                 if (c.deepsea) newcost = MAX_COST;
  594.                 else
  595.                     {
  596.                     if (tankshells > 6 * c.water) tankshells -= 6 * c.water;
  597.                     else tankshells = 1;
  598.                     new_timecost  += 7 * c.water;
  599.                     newcost = new_timecost + 100/tankshells + 200/tankarmour;
  600.                     if (newcost > MAX_COST) newcost = MAX_COST;
  601.                     }
  602.                 }
  603.             setcost(c,newcost);
  604.             if (do_showroute) showroute(c, newcost, !count_cost);
  605.             }
  606.         }
  607.     }
  608.  
  609. // ****************************************************************************
  610.  
  611. typedef void PAINT_FUNCTION(char x1, char x2, u_char32 row);
  612.  
  613. local void p_increment(char x1, char x2, u_char32 row)
  614.     {
  615.     if (x1 > COST_ARRAY_SIZE-1 || x2 < 0) return;
  616.     if (x1 < 0                ) x1 = 0;                    // clip to left edge
  617.     if (x2 > COST_ARRAY_SIZE-1) x2 = COST_ARRAY_SIZE-1;    // clip to right edge
  618.     while (x1<=x2) row[x1++]++;                            // increment hit counts in this row
  619.     }
  620.  
  621. local void p_clear(char x1, char x2, u_char32 row)
  622.     {
  623.     if (x1 > COST_ARRAY_SIZE-1 || x2 < 0) return;
  624.     if (x1 < 0                ) x1 = 0;                    // clip to left edge
  625.     if (x2 > COST_ARRAY_SIZE-1) x2 = COST_ARRAY_SIZE-1;    // clip to right edge
  626.     while (x1<=x2) row[x1++] = 0;                        // clear hit counts in this row
  627.     }
  628.  
  629. local void paint_circle(PAINT_FUNCTION p, BYTE cx, BYTE cy, BYTE radius)
  630.     {
  631.     BYTE x = radius, y = 0, y2 = radius;
  632.     short d = 1-radius;
  633.     if (IN_COSTARRAY(cy)) p(cx - x, cx + x, pillcoverage[cy]);
  634.     while (x>y)
  635.         {
  636.         if (d<0) d += 2*y+3; else { d += 2*(y-x)+5; x--; }
  637.         y++;
  638.         if (IN_COSTARRAY(cy+y)) p(cx - x, cx + x, pillcoverage[(BYTE)(cy + y)]);
  639.         if (IN_COSTARRAY(cy-y)) p(cx - x, cx + x, pillcoverage[(BYTE)(cy - y)]);
  640.         if (x<y2 && y<y2)
  641.             {
  642.             BYTE x2 = y-1;
  643.             if (IN_COSTARRAY(cy+y2)) p(cx - x2, cx + x2, pillcoverage[(BYTE)(cy + y2)]);
  644.             if (IN_COSTARRAY(cy-y2)) p(cx - x2, cx + x2, pillcoverage[(BYTE)(cy - y2)]);
  645.             y2--;
  646.             }
  647.         }
  648.     }
  649.  
  650. local void scan_boundary(CostPoint c, short direction)
  651.     {
  652.     int i;
  653.     BYTE *x = &c.x, *y = &c.y;
  654.     if (direction<0) { x = &c.y; y = &c.x; }
  655.     for (i=0; i<14; i++)
  656.         {
  657.         if ((*x) == 0 && (*y) > 0) (*y)--;
  658.         else if ((*y) == COST_ARRAY_SIZE-1) (*x)--;
  659.         else if ((*x) == COST_ARRAY_SIZE-1) (*y)++;
  660.         else if ((*y) == 0) (*x)++;
  661.         setcost(c, 0);
  662.         if (do_showroute) showroute(c, 0, 0);
  663.         }
  664.     }
  665.  
  666. // ****************************************************************************
  667.  
  668. local void constrain_subtarget(MAP_X *tx, MAP_Y *ty)
  669.     {
  670.     MAP_X costarray_rightedge  = costarray_left + COST_ARRAY_SIZE-1;
  671.     MAP_Y costarray_bottomedge = costarray_top  + COST_ARRAY_SIZE-1;
  672.     if      (*tx < costarray_left      ) *tx = costarray_left;
  673.     else if (*tx > costarray_rightedge ) *tx = costarray_rightedge;
  674.     if      (*ty < costarray_top       ) *ty = costarray_top;
  675.     else if (*ty > costarray_bottomedge) *ty = costarray_bottomedge;
  676.     }
  677.  
  678. // If we are *shooting* at something, ttype will indicate what it is, so that we
  679. // know we don't need to actually get there -- just get close enough to shoot it.
  680. local u_short make_costarray(OBJECT ttype, MAP_X tx, MAP_Y ty, BYTE shells, BYTE armour)
  681.     {
  682.     CostPoint subtarget;
  683.     ObjectInfo *ob;
  684.     int x,y;
  685.     
  686.     // This calculation might take half a second, so better stop the tank while we think
  687.     *(info->holdkeys) = *(info->tapkeys) = 0;
  688.     // (For the astute reader who says "Hey, you can't do that!" the answer is
  689.     // YES, these controls are 'live' -- they take effect immediately
  690.  
  691.     // Record info about this cost array
  692.     costarray_time = TickCount();
  693.     costarray_left = info->view_left;
  694.     costarray_top  = info->view_top;
  695.     costtarget_x   = subtarget_x = tx;
  696.     costtarget_y   = subtarget_y = ty;
  697.     costarray_boat = info->inboat;
  698.     costarray_targ = ttype;
  699.     constrain_subtarget(&subtarget_x, &subtarget_y);
  700.     
  701.     // Update tank local coordinates
  702.     ca_tankx = nearx - costarray_left;
  703.     ca_tanky = neary - costarray_top;
  704.  
  705.     // Check that tank falls within our visible region
  706.     // (eg, on pillbox view, tank may not be within view)
  707.     if (!IN_COSTARRAY(ca_tankx) || !IN_COSTARRAY(ca_tanky)) return(UNKNOWN_COST);
  708.  
  709.     // Initialize arrays
  710.     for (y=0; y<COST_ARRAY_SIZE; y++)
  711.         for (x=0; x<COST_ARRAY_SIZE; x++)
  712.             {
  713.             pillcoverage[y][x] = 0;
  714.             squarecost[y][x] = CPCost[y][x] = UNKNOWN_COST;
  715.             }
  716.     
  717.     for (ob=&info->objects[0]; ob<&info->objects[info->num_objects]; ob++)
  718.         if (ob->object == OBJECT_PILLBOX && ob->pillbox_strength > 0 &&
  719.             (ob->info & OBJECT_HOSTILE))
  720.                 {
  721.                 MAP_X x = ob->x >> 8;
  722.                 MAP_Y y = ob->y >> 8;
  723.                 paint_circle(p_increment, x-costarray_left, y-costarray_top, 8);
  724.                 paint_circle(p_increment, x-costarray_left, y-costarray_top, 6);
  725.                 paint_circle(p_increment, x-costarray_left, y-costarray_top, 4);
  726.                 }
  727.  
  728.     costarray_tankhits = pillcoverage[ca_tanky][ca_tankx];
  729.  
  730. // This code used to erase the target fire radius, before clear path finding was put
  731. // into the examine routine
  732. /*    if (ttype == OBJECT_PILLBOX || ttype == OBJECT_REFBASE)*/
  733. /*        paint_circle(p_clear, tx-costarray_left, ty-costarray_top, 7);*/
  734.  
  735.     if (do_showroute && 0)        // This is to show the pillbox fire coverage array
  736.         {
  737.         static const Pattern grey = { 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA };
  738.         static const Rect tanklocation = { 112, 112, 120, 120 };
  739.         CostPoint c;
  740.         ForeColor(blackColor);
  741.         for (c.y=0; c.y<COST_ARRAY_SIZE; c.y++)
  742.             for (c.x=0; c.x<COST_ARRAY_SIZE; c.x++)
  743.                 showroute(c, pillcoverage[c.y][c.x] * 16, 0);
  744.         Debugger();
  745.         ForeColor(blackColor);
  746.         FillRect(&routewindow->portRect, &qd.gray);
  747.         PaintOval(&tanklocation);
  748.         }
  749.  
  750.     // Start from (sub)target(s), with zero cost
  751.     subtarget.x       = subtarget_x - costarray_left;
  752.     subtarget.y       = subtarget_y - costarray_top;
  753.     subtarget.time    = 0;            // (when we arrive, we are there)
  754.     subtarget.shells  = shells;        // amount of shells and armour we want to arrive with
  755.     subtarget.armour  = armour * ARMOUR_UNIT_COST;
  756.     subtarget.water   = 0;
  757.     subtarget.deepsea = 0;
  758.     subtarget.cost    = 0;
  759.     
  760.     heap_size = 0;
  761.     setcost(subtarget, 0);
  762.     if (subtarget.x == 0 || subtarget.x == COST_ARRAY_SIZE-1 ||
  763.         subtarget.y == 0 || subtarget.y == COST_ARRAY_SIZE-1)
  764.             { scan_boundary(subtarget, 1); scan_boundary(subtarget, -1); }
  765.     while (heap_size)
  766.         {
  767.         CostPoint c = removefromheap();
  768.         // Exit when we find a path to the tank
  769.         if (c.x == ca_tankx && c.y == ca_tanky) return(c.cost);
  770.         // otherwise, continue the search outwards
  771.         c.y--; examine(c); c.y++;
  772.         c.x++; examine(c); c.x--;
  773.         c.y++; examine(c); c.y--;
  774.         c.x--; examine(c);
  775.         }
  776.     explain("No route from tank to %d, %d", nearx, neary);
  777.     //debug("No route from tank to %d, %d", nearx, neary);
  778.     return(MAX_COST);
  779.     }
  780.  
  781. // tx, ty say where we want to get to
  782. // shells and armour say how much weponry we would like to arrive with
  783. // returns FALSE if no route to the destination could be found
  784. // NOTE: If the tanks current armour is less than the requested arrival armour,
  785. // then ALL routes are failures. (The same hard rule does not apply to shells.)
  786. // The tank will of course attempt to preserve armour, even if the hard minimum is zero
  787. local Boolean find_best_route(OBJECT ttype, MAP_X tx, MAP_Y ty, BYTE shells, BYTE armour)
  788.     {
  789.     MAP_X subtarg_x = tx;
  790.     MAP_Y subtarg_y = ty;
  791.     int i, step = 1;
  792.     long bestx, besty;
  793.     u_short bestcost = MAX_COST;
  794.     TERRAIN best_terrain;
  795.     static MAP_X nodiagx;        // Don't consider diagonal movement
  796.     static MAP_Y nodiagy;        // when on this square
  797.     static long max_costarray_age = 120;    // start with two seconds
  798.     
  799.     if (info->armour < armour) { explain("Insufficient armour for this objective"); return(FALSE); }
  800.     
  801.     // If tank stuck in maze, or very close to a mine, then
  802.     // cutting corners with diagonal travel is not a good idea.
  803.     // Should proceed very cautiously, slowly, from square to square
  804.     if (info->tankobstructed || tank_close_to_mine || info->speed <= 0x18)
  805.         { nodiagx = nearx; nodiagy = neary; }
  806.     if (nodiagx == nearx && nodiagy == neary) step = 2;
  807.  
  808.     ca_tankx = nearx - costarray_left;
  809.     ca_tanky = neary - costarray_top;
  810.     
  811.     // If array is old, or for the wrong target, or wrong type of cost
  812.     // array, or tank has moved too close to the edge, make a new one
  813.     constrain_subtarget(&subtarg_x, &subtarg_y);
  814.     if (TimeNow - costarray_time > max_costarray_age ||
  815.         subtarget_x != subtarg_x || subtarget_y != subtarg_y ||
  816.         costarray_boat != info->inboat || costarray_targ != ttype ||
  817.         ca_tankx < 7 || ca_tankx >= COST_ARRAY_SIZE-7 ||
  818.         ca_tanky < 7 || ca_tanky >= COST_ARRAY_SIZE-7)
  819.         {
  820.         static const Pattern grey = { 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA };
  821.         static const Rect tanklocation = { 112, 112, 120, 120 };
  822.         u_short cost;
  823.         GrafPtr old;
  824.         if (do_showroute)
  825.             {
  826.             GetPort(&old);
  827.             SetPort(routewindow);
  828.             ForeColor(blackColor);
  829.             FillRect(&routewindow->portRect, &qd.gray);
  830.             PaintOval(&tanklocation);
  831.             }
  832.         cost = make_costarray(ttype,tx,ty,shells,armour);
  833.         if (do_showroute)
  834.             {
  835.             if (costarray_boat) ForeColor(whiteColor);
  836.             else ForeColor(blackColor);
  837.             PaintOval(&tanklocation);
  838.             SetPort(old);
  839.             }
  840.         // Don't want to spend more than 5% of our time calculating cost arrays
  841.         max_costarray_age = (TickCount() - costarray_time) * 20;
  842.         if (max_costarray_age < 60 ) max_costarray_age = 60;
  843.         if (max_costarray_age > 500) max_costarray_age = 500;
  844.         if (cost == MAX_COST) return(FALSE);
  845.         }
  846.  
  847.     for (i=0; i<8; i+=step)
  848.         {
  849.         BYTE x = ca_tankx+surrounding.s.s8[i].x;
  850.         BYTE y = ca_tanky+surrounding.s.s8[i].y;
  851.         if (IN_COSTARRAY(x) && IN_COSTARRAY(y) && bestcost > squarecost[y][x])
  852.                 {
  853.                 bestcost = squarecost[y][x];
  854.                 bestx = ((WORLD_X)(x + costarray_left)<<8) + 0x80;
  855.                 besty = ((WORLD_Y)(y + costarray_top )<<8) + 0x80;
  856.                 }
  857.         }
  858.     i = aim(bestx - (long)info->tankx, besty - (long)info->tanky);
  859.     i = i + 8 >> 4 & 0xF;
  860.     direction_votes[i] += 100;
  861.     best_terrain = getmapcellW(bestx,besty);
  862.     if (!info->inboat)
  863.         {
  864.         if (best_terrain == BOAT) direction_maxspeeds[i] = 32;
  865.         // if (best_terrain == RIVER && info->trees > ?) build a bridge, or a boat??
  866.         }
  867.     return(TRUE);
  868.     }
  869.  
  870. // ****************************************************************************
  871.  
  872. // Code to think about objects on the screen
  873.  
  874. // Calling reset_progress unconditionally resets 'progress' count
  875. // and ignores object for 'ignoretime' ticks. (ignoretime==0 means *don't* ignore)
  876. local void reset_progress(ProgressInfo *p, long ignoretime)
  877.     {
  878.     p->remaining_progress = MAX_PROGRESS;
  879.     // Must forward set last_progress time, or we risk having it
  880.     // marked 'boring' the moment the ingore timer expires
  881.     p->last_progress = TimeNow + ignoretime;
  882.     p->ignore_until  = TimeNow + ignoretime;
  883.     }
  884.  
  885. // returns TRUE if still making progress
  886. local Boolean register_progress(ProgressInfo *p, u_long remaining)
  887.     {
  888.     // if we are still making progress, or this is a stale record that
  889.     // we haven't touched for a long time, then update it
  890.     if (remaining < p->remaining_progress || TimeNow - p->last_progress > ATTENTION_SPAN * 2)
  891.         {
  892.         p->remaining_progress = remaining;
  893.         p->last_progress = TimeNow;
  894.         }
  895.     else if (TimeNow - p->last_progress > ATTENTION_SPAN)
  896.         {
  897.         explain("No progress");
  898.         reset_progress(p, boredomtime);
  899.         return(FALSE);
  900.         }
  901.     return(TRUE);
  902.     }
  903.  
  904. local void decide_shooting(OBJECT what, u_long dist, long tx, long ty, short strength)
  905.     {
  906.     if (info->shells)
  907.         {
  908.         shootwhat = what;
  909.         shoot_path_costs = moving_target_path;
  910.         if      (what == OBJECT_PILLBOX) shoot_path_costs = stationary_target_path;
  911.         else if (what == OBJECT_REFBASE) shoot_path_costs = stationary_target_path;
  912.         // Shootsoon is a safety so that the man does not
  913.         // leave the tank just as we are about to engage an enemy
  914.         if (dist < 0x900) shootsoon = TRUE;
  915.         if (dist < 0x200) shootit = TRUE;
  916.         else if (dist < 0x780)
  917.             {
  918.             short cost = path_cost(info->tankx, info->tanky, shoot_path_costs, tx, ty, 0x7FFF);
  919.             if (cost == 0 || strength + 2 * cost < info->shells) shootit = TRUE;
  920.             }
  921.         }
  922.     }
  923.  
  924. // Note: mustn't set "shells" (the target requirement) greater than 20 (wanted_shells)
  925. // or the tank may decide that it doesn't want to refuel because it has > 20 shells
  926. // but decides it cannot attack its target because it has < (say) 30 shells
  927.  
  928. local u_long check_objects(void)
  929.     {
  930.     int i;
  931.     long tx, ty;
  932.     BYTE shells = 10, armour = 0;
  933.     ProgressInfo dummy;
  934.     ProgressInfo *progresstarget = &dummy;
  935.     ObjectInfo *ob;
  936.     ObjectInfo *nearest_tank = NULL;
  937.     ObjectInfo *nearest_pill = NULL, *nearest_frnd   = NULL;
  938.     ObjectInfo *nearest_base = NULL, *nearest_refuel = NULL;
  939.     u_long dist;
  940.     u_long max_dist = (s.explore || s.attacktanks || s.attackpills || s.attackbases)
  941.         ? MAX_VIS_RANGE : DEFENSIVE_RANGE;
  942.     u_long tankd = max_dist, pilld = max_dist, frndd = max_dist;
  943.     u_long based = max_dist, refueld = max_dist;
  944.     u_long limit_dist = max_dist;
  945.     Boolean decided = FALSE;
  946.     BYTE wanted_shells = 30, useful_shells = 6;
  947.     static BYTE last_armour_value = 0;
  948.     
  949.     // If we are on a refuelling base then we want full shells, and we wait
  950.     // until we have got every last shell from the base, otherwise we
  951.     // will put up with as few as 20 for general trundling around the map
  952.     // and not be attracted by bases that have less than 6 shells to give.
  953.     if (getmapcellW(info->tankx, info->tanky) == REFBASE_T)
  954.         { wanted_shells = 40; useful_shells = 1; }
  955.     
  956.     // If we have some information about a nearby base (which we are not ignoring)
  957.     if (info->base && TimeNow - baseprogress[info->base->idnum].ignore_until >= 0)
  958.         {
  959.         dist = objectrange_to_me(info->base);
  960.  
  961.         // The following two apply to bases we are sitting on
  962.         if (dist < 0x80)
  963.             {
  964.             // If we are losing armour (being shot somehow) then ditch this base
  965.             if (info->armour < last_armour_value)
  966.                 {
  967.                 reset_progress(&baseprogress[info->base->idnum], boredomtime);
  968.                 explain("Abandon base! %d, %d", info->armour, last_armour_value);
  969.                 }
  970.             // If base has just fully refuelled us, mark it is "not boring"
  971.             if (info->shells == 40 && info->armour == 8)
  972.                 reset_progress(&baseprogress[info->base->idnum], 0);
  973.             }
  974.         
  975.         // Do we WANT to refuel?
  976.         if ((info->shells < wanted_shells || info->armour < 8) && safe_base(info->base))
  977.             {
  978.             // OK, if base can supply the requirements, make it the "nearest_refuel"
  979.             Boolean get_shells = (info->shells < wanted_shells && info->base_shells >= useful_shells);
  980.             Boolean get_armour = (info->armour < 8             && info->base_armour > MIN_BASE_ARMOUR);
  981.             if (get_shells || get_armour) { nearest_refuel = info->base; refueld = dist; }
  982.             else
  983.                 {
  984.                 explain("Refuelling base exhausted");
  985.                 reset_progress(&baseprogress[info->base->idnum], boredomtime);
  986.                 }
  987.             // else if base can't supply the requirements, mark it boring, so that
  988.             // after we go far enough away to lose status reporting from it,
  989.             // we still know not to bother coming back here for a while
  990.             }
  991.         }
  992.  
  993.     last_armour_value = info->armour;
  994.  
  995. // bug fix for 0.99.2b
  996. #define GOODTANK (ob->x > 0x1000 && ob->x < 0xF000 && ob->y > 0x1000 && ob->y < 0xF000)
  997.  
  998.     for (ob=&info->objects[0]; ob<&info->objects[info->num_objects]; ob++)
  999.         {
  1000.         switch (ob->object)
  1001.             {
  1002.             case OBJECT_TANK:
  1003.                 if (GOODTANK && TimeNow - tankprogress[ob->idnum].ignore_until >= 0)
  1004.                     if (ob->info & OBJECT_HOSTILE)
  1005.                         if ((dist = objectrange_to_me(ob)) < tankd)
  1006.                             { nearest_tank = ob; tankd = dist; }
  1007.                 break;
  1008.             case OBJECT_PILLBOX:
  1009.                 if (ob->pillbox_strength > 0 &&
  1010.                     pillprogress[ob->idnum].ignore_until - TimeNow > boredomtime)
  1011.                         reset_progress(&pillprogress[ob->idnum], boredomtime);
  1012.                 if (TimeNow - pillprogress[ob->idnum].ignore_until >= 0)
  1013.                     {
  1014.                     short strength = ob->pillbox_strength;
  1015.                     dist = objectrange_to_me(ob);
  1016.                     if (strength == 0)                        // Dead pillboxes
  1017.                         {
  1018.                         dist += 16*256;
  1019.                         if (fatal_x == ob->x >> 8 && fatal_y == ob->y >> 8)
  1020.                             reset_progress(&pillprogress[ob->idnum], 6*60*60*60);
  1021.                         else if (dist < pilld) { nearest_pill = ob; pilld = dist; }
  1022.                         }
  1023.                     else if (ob->info & OBJECT_HOSTILE)        // Hostile pillboxes
  1024.                         {
  1025.                         dist += strength*256;
  1026.                         if (dist < pilld) { nearest_pill = ob; pilld = dist; }
  1027.                         }
  1028.                     else if (strength < 15)                    // Friendly damaged pillbox
  1029.                         {
  1030.                         if ((dist = objectrange_to_me(ob)) < frndd)
  1031.                             { nearest_frnd = ob; frndd = dist; }
  1032.                         }
  1033.                     }
  1034.                 break;
  1035.             case OBJECT_REFBASE:
  1036.                 if (TimeNow - baseprogress[ob->idnum].ignore_until >= 0 && ob != info->base)
  1037.                     {
  1038.                     if (ob->info & OBJECT_HOSTILE)
  1039.                         {
  1040.                         if (s.attackbases && info->shells)
  1041.                             if ((dist = objectrange_to_me(ob)) < based)
  1042.                                 { nearest_base = ob; based = dist; }
  1043.                         }
  1044.                     else
  1045.                         {
  1046.                         if (info->shells < wanted_shells || info->armour < 8)
  1047.                             if ((dist = objectrange_to_me(ob)) < refueld && safe_base(ob))
  1048.                                 { nearest_refuel = ob; refueld = dist; }
  1049.                         }
  1050.                     }
  1051.                 break;
  1052.             }
  1053.         }
  1054.     
  1055.     // pilld was weighted to account for pillbox strength -- fix it now
  1056.     if (nearest_pill) pilld = objectrange_to_me(nearest_pill);
  1057.     // (We prefer to attack weak pillboxes instad of strong ones, except dead
  1058.     // pillboxes get left till last because they pose no immediate threat.)
  1059.  
  1060.     // If damaged pillbox nearby, fix it
  1061.     if (s.repairpills && nearest_frnd && frndd < DEFENSIVE_RANGE &&
  1062.         info->trees && CAN_DO_BUILDING && MAN_PATH(nearest_frnd->x, nearest_frnd->y))
  1063.         {
  1064.         info->build->x = nearest_frnd->x >> 8;
  1065.         info->build->y = nearest_frnd->y >> 8;
  1066.         info->build->action = BUILDMODE_PBOX;
  1067.         }
  1068.  
  1069.     // If carrying a pillbox, and we have a hostile tank nearby, use it?
  1070.     if (CAN_BUILD_PILLBOX && s.ppoffensive && tankd < 0xD00)
  1071.         {
  1072.         MAP_X x = (info->tankx + nearest_tank->x) >> 9;
  1073.         MAP_Y y = (info->tanky + nearest_tank->y) >> 9;
  1074.         TERRAIN raw = raw_getmapcell(x, y);
  1075.         if (!(raw & TERRAIN_MINE) && can_build_pillbox[raw & TERRAIN_MASK] &&
  1076.             MAN_PATH((WORLD_X)x<<8, (WORLD_Y)y<<8))
  1077.             {
  1078.             info->build->x = x;
  1079.             info->build->y = y;
  1080.             info->build->action = BUILDMODE_PBOX;
  1081.             }
  1082.         }
  1083.  
  1084.     if (limit_dist > based  ) limit_dist = based;
  1085.     if (limit_dist > refueld) limit_dist = refueld;
  1086.     limit_dist = (limit_dist * 2) + DEFENSIVE_RANGE;
  1087.     if (limit_dist > max_dist) limit_dist = max_dist;
  1088.     // limit_dist is to limit our search, so we don't go to
  1089.     // the other side of the map for a dead pillbox when
  1090.     // there is something more important right next to us.
  1091.  
  1092.     // Special priority: don't leave man outside tank
  1093.     if (TimeNow - manrescueprogress.ignore_until >= 0 && info->man_status > 1)
  1094.         {
  1095.         tx = info->man_x;
  1096.         ty = info->man_y;
  1097.         dist = findrange(tx, ty, info->tankx, info->tanky);
  1098.         progresstarget = &manrescueprogress;
  1099.         if (info->manobstructed || dist > 0x200) { decided = TRUE; explain("Rescuing Man"); }
  1100.         }
  1101.  
  1102.     // First priority: hostile tanks/pillboxes which are within shooting range
  1103.     
  1104.     // If we have a nearby tank, but we're not attacking tanks, cancel it
  1105.     if (tankd < limit_dist && !s.attacktanks) tankd = limit_dist;
  1106.  
  1107.     // If we have a nearby pillbox, but we're not attacking pillboxes, cancel it
  1108.     // (unless it is a complete pushover)
  1109.     if (pilld < limit_dist && !s.attackpills)
  1110.         if (nearest_pill->pillbox_strength > info->armour ||
  1111.             nearest_pill->pillbox_strength > info->shells * 2) pilld = limit_dist;
  1112.  
  1113.     if (!decided && (tankd < limit_dist || pilld < limit_dist))
  1114.         {
  1115.         if (tankd < pilld)    // We have a hostile tank approaching
  1116.             {
  1117.             BYTE required_armour = (tankd > DEFENSIVE_RANGE) ? 6 : incoming_shells;
  1118.             Boolean wants_fight = info->shells > 5 && info->armour > required_armour;
  1119.             if (tankd < 0x800 || wants_fight)
  1120.                 {
  1121.                 dist = tankd;
  1122.                 tx = nearest_tank->x;
  1123.                 ty = nearest_tank->y;
  1124.                 progresstarget = &tankprogress[nearest_tank->idnum];
  1125.                 // No special register_progress -- just be content to close distance
  1126.                 decided = TRUE;
  1127.                 if (wants_fight)
  1128.                     {
  1129.                     shells = 20; armour = required_armour;
  1130.                     explain("Attacking tank: %lu, %lu (%ld, %ld)",
  1131.                         tx>>8, ty>>8, (tx-info->tankx)>>8, (ty-info->tanky)>>8);
  1132.                     decide_shooting(OBJECT_TANK, dist, tx, ty, 9);
  1133.                     }
  1134.                 else
  1135.                     {
  1136.                     explain("Fleeing tank: %lu, %lu (%ld, %ld)",
  1137.                         tx>>8, ty>>8, (tx-info->tankx)>>8, (ty-info->tanky)>>8);
  1138.                     runaway = TRUE;
  1139.                     }
  1140.                 }
  1141.             }
  1142.         else                // Nearest thing is a hostile pillbox
  1143.             {
  1144.             BYTE strength = nearest_pill->pillbox_strength;
  1145.             BYTE required_shells = strength + strength/2;
  1146.             BYTE required_armour = incoming_shells + strength ? (2 + (strength+2)/3) : 0;
  1147.             
  1148.             // ???? required_armour USED to say this:
  1149.             // (pilld > DEFENSIVE_RANGE) ? 6 : incoming_shells + 1 + strength/4;
  1150.             // but this made it afraid to pick up dead pillboxes if tank had no armour!
  1151.             
  1152.             Boolean wants_fight = info->shells >= strength && info->armour >= required_armour;
  1153.             
  1154.             // Consider pillbox if any of:
  1155.             // 1. It is dangerously close (do I still need this?)
  1156.             // 2. Want to fight it
  1157.             // 3. It's fighting us
  1158.             // 4. It is dead and waiting to be picked up
  1159.             if (/*pilld < 0x400 || */wants_fight || incoming_shells > 1 || strength == 0)
  1160.                 {
  1161.                 dist = pilld;
  1162.                 tx = nearest_pill->x;
  1163.                 ty = nearest_pill->y;
  1164.                 progresstarget = &pillprogress[nearest_pill->idnum];
  1165.                 if (pilld < 0x180 && strength == 0)
  1166.                     { pillpickup_x = tx>>8; pillpickup_y = ty>>8; }
  1167.                 decided = TRUE;
  1168.                 if (wants_fight)
  1169.                     {
  1170.                     shells = 20; armour = required_armour;
  1171.                     explain("Attacking pill: %lu, %lu (%ld, %ld)",
  1172.                         tx>>8, ty>>8, (tx-info->tankx)>>8, (ty-info->tanky)>>8);
  1173.                     if (strength > 0) decide_shooting(OBJECT_PILLBOX, dist, tx, ty, strength);
  1174.                     if (shootit) register_progress(progresstarget, strength);
  1175.                     // If we are going to shoot the pillbox, then our criterion of
  1176.                     // making progress is whether we are inflicting any damage
  1177.                     }
  1178.                 else
  1179.                     {
  1180.                     explain("Fleeing pill: %lu, %lu (%ld, %ld)",
  1181.                         tx>>8, ty>>8, (tx-info->tankx)>>8, (ty-info->tanky)>>8);
  1182.                     runaway = TRUE;
  1183.                     }
  1184.                 }
  1185.             }
  1186.         }
  1187.  
  1188.     // Second priority: Attack some enemy bases
  1189.     if (!decided && based < limit_dist)
  1190.         {
  1191.         dist = based;
  1192.         tx = nearest_base->x;
  1193.         ty = nearest_base->y;
  1194.         progresstarget = &baseprogress[nearest_base->idnum];
  1195.         decided = TRUE;
  1196.         explain("Attack Base: %lu, %lu (%ld, %ld)",
  1197.             tx>>8, ty>>8, (tx-info->tankx)>>8, (ty-info->tanky)>>8);
  1198.         shells = 20; armour = 0;    // Don't need armour, but do need lots of shells
  1199.         if (nearest_base->refbase_strength) decide_shooting(OBJECT_REFBASE, dist, tx, ty, 30);
  1200.         }
  1201.  
  1202.     // Third priority: Do we need to refuel?
  1203.     if (!decided && refueld < limit_dist)
  1204.         {
  1205.         dist = refueld;
  1206.         tx = nearest_refuel->x;
  1207.         ty = nearest_refuel->y;
  1208.         progresstarget = &baseprogress[nearest_refuel->idnum];
  1209.         // If we're on base; don't get bored
  1210.         if (dist < 0x80)
  1211.             {
  1212.             register_progress(progresstarget, 80 - info->shells - info->armour*5);
  1213.             for (i=0; i<16; i++) target_distances[i] = 0;
  1214.             }
  1215.         decided = TRUE;
  1216.         explain("Refuel: %lu, %lu (%ld, %ld)",
  1217.             tx>>8, ty>>8, (tx-info->tankx)>>8, (ty-info->tanky)>>8);
  1218.         shells = 0; armour = 0;    // Don't care what we arrive with, just get us there
  1219.         }
  1220.  
  1221.     // If not decided on anything, then there is nothing to be bored with
  1222.     if (!decided)
  1223.         {
  1224.         if (!s.explore) for (i=0; i<16; i++) target_distances[i] = 0;
  1225.         return(MAX_VIS_RANGE);
  1226.         }
  1227.     
  1228.     register_progress(progresstarget, dist);
  1229.     
  1230.     shoot_direction = aim(tx - (long)info->tankx, ty - (long)info->tanky);
  1231.     shoot_dir_vote  = shoot_direction + 8 >> 4 & 0xF;
  1232.     if (runaway)
  1233.         {
  1234.         reset_progress(progresstarget, 0);    // Don't get bored while running away!
  1235.         for (i=-4; i<=4; i++) direction_votes[shoot_dir_vote+i & 0xF] -= 20;
  1236.         for (i=5; i<=11; i++) direction_votes[shoot_dir_vote+i & 0xF] += 20;
  1237.         }
  1238.     else
  1239.         {
  1240.         target_distances[shoot_dir_vote] = dist;
  1241.         // If shooting or VERY close to target then lock on directly
  1242.         if (shootit || dist < 0x100) direction_votes[shoot_dir_vote] += 100;
  1243.         else
  1244.             {
  1245.             // find best route to target, if possible
  1246.             if (!find_best_route(shootwhat, tx>>8, ty>>8, shells, armour))
  1247.                 {
  1248.                 explain("No route");
  1249.                 reset_progress(progresstarget, boredomtime);
  1250.                 }
  1251.             return(0);
  1252.             // Return zero to override normal terrain evaluation
  1253.             }
  1254.         }
  1255.     return(dist);
  1256.     }
  1257.  
  1258. // ****************************************************************************
  1259.  
  1260. // Code to actively explore the map for things to do
  1261.  
  1262. local void setscout(void)
  1263.     {
  1264.     // Pick a new location to head towards
  1265.     scoutx = 53 + 10 * (TimeNow & 15);
  1266.     scouty = 53 + 10 * (TimeNow>>4 & 15);
  1267.     explain("Scouting %d,%d", scoutx, scouty);
  1268.     reset_progress(&scoutingprogress, 0);
  1269.     }
  1270.  
  1271. local void scout(void)
  1272.     {
  1273.     u_long dist = findrange((WORLD_X)scoutx << 8, (WORLD_Y)scouty << 8,
  1274.                                                 info->tankx, info->tanky);
  1275.  
  1276.     if (!register_progress(&scoutingprogress, dist)) setscout();
  1277.     
  1278.     // if at scout target, pick another one
  1279.     if (nearx == scoutx && neary == scouty)
  1280.         {
  1281.         explain("Arrived (Scouting %d,%d)", scoutx, scouty);
  1282.         setscout();
  1283.         }
  1284.  
  1285.     // If failed to find route, or route goes into deep sea, pick another scout target
  1286.     if (!find_best_route(-1, scoutx, scouty, 10, 2) ||
  1287.         getmapcellM(subtarget_x, subtarget_y) == DEEPSEA)
  1288.             {
  1289.             explain("No route (Scouting %d,%d)", scoutx, scouty);
  1290.             setscout();
  1291.             }
  1292.     }
  1293.  
  1294. // ****************************************************************************
  1295.  
  1296. // Code to think about what kind of terrain we should try to get/stay on
  1297. // Simple kind of insect behaviour -- just look at the nearby terrain and
  1298. // decide which is nicest
  1299.  
  1300. local long terrain_desirability[NUM_TERRAINS] =
  1301.     {
  1302.     -10, -2, -1, -1,    // BUILDING, RIVER, SWAMP, CRATER
  1303.     5, 0, -1, 0,        // ROAD, FOREST, RUBBLE, GRASS,
  1304.     -10, 1, -100, 0,    // HALFBUILDING, BOAT, DEEPSEA, REFBASE_T,
  1305.     -10, -10            // PILLBOX_T, TERRAIN_UNKNOWN
  1306.     };
  1307.  
  1308. #define desirability(X,Y) \
  1309. (terrain_desirability[getmapcellM((X),(Y))] + (checkmineM((X),(Y)) ? -500 : 0))
  1310.  
  1311. local void check_terrain(void)
  1312.     {
  1313.     int i;
  1314.     long des = desirability(nearx, neary);
  1315.     terrain_desirability[RIVER  ] = info->inboat ? 0 : -2;
  1316.     terrain_desirability[DEEPSEA] = info->inboat ? -10 : -100;
  1317.     for (i=0; i<8; i++)
  1318.         {
  1319.         long val = desirability(nearx+surrounding.s.s8[i].x,
  1320.                                 neary+surrounding.s.s8[i].y) - des;
  1321.         direction_votes[i*2-2 & 0xF] += val;
  1322.         direction_votes[i*2-1 & 0xF] += val*2;
  1323.         direction_votes[i*2        ] += val*5;
  1324.         direction_votes[i*2+1      ] += val*2;
  1325.         direction_votes[i*2+2 & 0xF] += val;
  1326.         }
  1327.  
  1328.     for (i=0; i<16; i++)
  1329.         {
  1330.         long val = desirability(nearx+surrounding.s.s16[i].x,
  1331.                                 neary+surrounding.s.s16[i].y) - des;
  1332.         direction_votes[i-1 & 0xF] += val>>1;
  1333.         direction_votes[i        ] += val;
  1334.         direction_votes[i+1 & 0xF] += val>>1;
  1335.         }
  1336.  
  1337.     // If on road, try to keep tank centred.
  1338.     if (getmapcellM(nearx,neary) == ROAD)
  1339.         {
  1340.         Boolean go_down  = getmapcellW(info->tankx, info->tanky - 0x60) != ROAD;
  1341.         Boolean go_up    = getmapcellW(info->tankx, info->tanky + 0x60) != ROAD;
  1342.         Boolean go_right = getmapcellW(info->tankx - 0x60, info->tanky) != ROAD;
  1343.         Boolean go_left  = getmapcellW(info->tankx + 0x60, info->tanky) != ROAD;
  1344.         if (go_down + go_up + go_right + go_left == 1)
  1345.             {
  1346.             BYTE dir = go_right * 4 + go_down * 8 + go_left * 12;
  1347.             for (i=-3; i<=3; i++) direction_votes[dir+i & 0xF] += 10;
  1348.             }
  1349.         }
  1350.     }
  1351.  
  1352. // ****************************************************************************
  1353.  
  1354. // Code to organize voting about which direction we should be going in
  1355.  
  1356. local void cast_votes(void)
  1357.     {
  1358.     u_long target_distance;
  1359.     BYTE d = info->direction + 8 >> 4 & 0xF;
  1360.  
  1361.     // If we are clearing mines, and we are dangerously close
  1362.     // to a mine right now, should just try to get off it so
  1363.     // that we get a chance for a safe shot at it.
  1364.     if (s.clearmines && info->shells && tank_close_to_mine)
  1365.         { check_terrain(); return; }
  1366.  
  1367.     // Bias towards continuing in the same direction
  1368.     direction_votes[d-1 & 0xF] += 1;
  1369.     direction_votes[d+0 & 0xF] += 2;
  1370.     direction_votes[d+1 & 0xF] += 1;
  1371.     direction_votes[d+7 & 0xF] -= 5;
  1372.     direction_votes[d+8 & 0xF] -=10;
  1373.     direction_votes[d+9 & 0xF] -= 5;
  1374.  
  1375.     target_distance = check_objects();
  1376.     
  1377.     // If only one square between us and the hostile,
  1378.     // then terrain doesn't matter any more
  1379.     if (target_distance < 0x180) return;
  1380.     
  1381.     // If nothing within sight, then explore?
  1382.     if (target_distance == MAX_VIS_RANGE && s.explore) scout();
  1383.     else            // else just make local decision
  1384.         {
  1385.         if (still_on_boat) direction_votes[land_direction>>4] += 20;
  1386.         check_terrain();
  1387.         }
  1388.     }
  1389.  
  1390. // ****************************************************************************
  1391.  
  1392. // Code to build bridges etc where necessary. Returns TRUE if decided to build
  1393.  
  1394. local Boolean decide_building(MAP_X x, MAP_Y y)
  1395.     {
  1396.     TERRAIN raw = raw_getmapcell(x, y);
  1397.     if (raw & TERRAIN_MINE) return;
  1398.     info->build->x = x;
  1399.     info->build->y = y;
  1400.     switch (raw & TERRAIN_MASK)
  1401.         {
  1402.         case RIVER    :
  1403.         case SWAMP    :
  1404.         case CRATER   :
  1405.         case RUBBLE   : if (info->trees >= 2)
  1406.                             info->build->action = BUILDMODE_ROAD;
  1407.                         break;
  1408.         case FOREST   : if (info->trees < 40)
  1409.                             info->build->action = BUILDMODE_FARM;
  1410.                         break;
  1411.         }
  1412.     return(info->build->action != 0);
  1413.     }
  1414.  
  1415. // ****************************************************************************
  1416.  
  1417. // Code to clear mines from in front of the tank
  1418.  
  1419. local MAP_X shotminex;        // Mine we have just shot at -- so ignore it
  1420. local MAP_Y shotminey;        // when looking for other mines to shoot
  1421. local long shotminetime;    // because it will be gone in a moment.
  1422.  
  1423. local MAP_X currentminex;    // The mine we plan to shoot at next
  1424. local MAP_Y currentminey;
  1425.  
  1426. // Don't even consider trying to hit mines more than 0x60 from the centre.
  1427. #define MINE_HIT_ERROR_LIMIT 0x60
  1428.  
  1429. local void minesweep(Boolean *foundmine, Boolean *doshoot)
  1430.     {
  1431.     char a, best_a;
  1432.     short r, best_r = 0;
  1433.     
  1434.     // Want to try to hit mines as close to the centre as possible.
  1435.     BYTE best_hit = MINE_HIT_ERROR_LIMIT;
  1436.     
  1437.     // If we already have something to shoot at, only worry about nearby mines
  1438.     short max_range = shootit ? 6 : 12;
  1439.     
  1440.     if (TimeNow - shotminetime > 60) shotminex = 0;
  1441.     // After shooting at a mine, if, for some unknown reason, it is not
  1442.     // gone within one second, then we should take another shot at it
  1443.     
  1444.     for (a = -32; a<=32; a+=8)    // sweep left and right of where tank is going
  1445.         {
  1446.         Boolean through_forest = FALSE;
  1447.         for (r=2; r<max_range; r++)    // check up to max_range in front of tank
  1448.             {
  1449.             WORLD_X wx = info->tankx + sin(chosen_direction + a) * r;
  1450.             WORLD_Y wy = info->tanky - cos(chosen_direction + a) * r;
  1451.             MAP_X x = wx >> 8;        // x,y are square we are checking
  1452.             MAP_Y y = wy >> 8;
  1453.             TERRAIN raw = raw_getmapcell(x, y);
  1454.             TERRAIN t = raw & TERRAIN_MASK;
  1455.             
  1456.             // Don't try to shoot through buildings or pillboxes
  1457.             if (t == BUILDING || t == HALFBUILDING || t == PILLBOX_T) break;
  1458.             
  1459.             if (raw & TERRAIN_MINE)        // If there is a mine on this square...
  1460.                 {
  1461.                 // Calculate how far from centre of square the shell will land
  1462.                 BYTE dx = wx & 0xFF;    // dx,dy indicate position within square
  1463.                 BYTE dy = wy & 0xFF;
  1464.                 if (dx > 0x80) dx = dx-0x80; else dx = 0x80-dx;
  1465.                 if (dy > 0x80) dy = dy-0x80; else dy = 0x80-dy;
  1466.                 if (dx < dy) dx = dy;
  1467.                 
  1468.                 if (dx < MINE_HIT_ERROR_LIMIT)    // We want to shoot this
  1469.                     {
  1470.                     // Don't shoot the mine if we are so close it would damage us
  1471.                     if ((x == tankleftx || x == tankrightx) &&
  1472.                         (y == tanktopy  || y == tankbottomy)) continue;
  1473.                     
  1474.                     // If there is a mine very close to us, then take note of it
  1475.                     // even if we can't (or don't want to) shoot it immediately.
  1476.                     if (r<4) *foundmine = TRUE;
  1477.                     
  1478.                     // If we have already shot at the mine, ignore it (for now).
  1479.                     if (x == shotminex && y == shotminey) continue;
  1480.                     
  1481.                     // See if this is our best chance at a clean hit
  1482.                     if (best_hit > dx)
  1483.                         {
  1484.                         best_hit = dx;
  1485.                         best_r = r;
  1486.                         best_a = a;
  1487.                         // If firing through forest, we need multiple shots
  1488.                         // so don't assume shot will hit the mine first time
  1489.                         if (through_forest) currentminex = 0;
  1490.                         else { currentminex = x; currentminey = y; }
  1491.                         }
  1492.                     }
  1493.                 }
  1494.  
  1495.             // If shot would pass through forest, make a note of the fact
  1496.             if (t == FOREST) through_forest = TRUE;
  1497.             
  1498.             // If we are on a boat, we can't shoot past the shore
  1499.             if (info->inboat && t != RIVER && t != DEEPSEA) break;
  1500.             }
  1501.         }
  1502.  
  1503.     if (best_r)
  1504.         {
  1505.         chosen_gunrange = best_r;
  1506.         chosen_direction = chosen_direction + best_a;
  1507.         *foundmine = *doshoot = TRUE;
  1508.         }
  1509.     }
  1510.  
  1511. // ****************************************************************************
  1512.  
  1513. // A bit of geometry, to see if man lies close to path of shot
  1514.  
  1515. local Boolean man_clear_of_shot(void)
  1516.     {
  1517.     long x = (long)info->man_x - (long)info->tankx;        // displacement of man relative to tank
  1518.     long y = (long)info->man_y - (long)info->tanky;
  1519.     // Now do scalar product with tank's (unit) direction vector to find
  1520.     // the point on the line of the shot path which is closest to the man
  1521.     long d = (x * sin(info->direction) - y * cos(info->direction)) >> 7;
  1522.     //debug("Man at %ld, %ld, range %ld, error %ld;g", x, y, d);
  1523.     // Now make x and y be the displacement of the man relative to that
  1524.     // closest point (calculated by d times the unit direction vector).
  1525.     x -= (d * sin(info->direction)) >> 7;
  1526.     y += (d * cos(info->direction)) >> 7;    // (plus because x=sin, y=-cos)
  1527.     //debug("Man range %ld, error %ld;g", d, sqrt(x*x + y*y));
  1528.     // Man is safe if he is:
  1529.     // 1. Somewhere behind the tank
  1530.     // 2. More than ten squares in front of the tank
  1531.     // 3. More than two squares either side of the path of the shot
  1532.     return(d < 0 || d > 2560 || sqrt(x*x + y*y) > 512);
  1533.     }
  1534.  
  1535. // Code to count the votes and decide what action to take
  1536.  
  1537. local void count_votes(void)
  1538.     {
  1539.     int i, best = 0;
  1540.     u_long target_distance;
  1541.     u_long desired_dist = 0x20;    // Approach bases gently, and don't overshoot
  1542.     BYTE max_speed;
  1543.     char correction = 0;
  1544.     Boolean panic = (getmapcellM(nearx,neary) == RIVER || /*info->inboat || */runaway);
  1545.     Boolean gofaster = FALSE, goslower = FALSE;
  1546.     Boolean fullstop = FALSE, killmine = FALSE;
  1547.  
  1548.     for (i=1; i<16; i++) if (direction_votes[best] < direction_votes[i]) best = i;
  1549.  
  1550.     if (best == shoot_dir_vote) chosen_direction = shoot_direction;
  1551.     else { chosen_direction = best<<4; shootit = FALSE; }
  1552.     target_distance = target_distances[best];
  1553.     max_speed = direction_maxspeeds[best];
  1554.  
  1555.     // If we have some shells, and we are not on a mine,
  1556.     // then think about clearing mines
  1557.     if (s.clearmines && info->shells && !checkmineM(nearx,neary))
  1558.         minesweep(&killmine, &shootit);
  1559.  
  1560.     if (target_distance > 0x20 || killmine)
  1561.         correction = (char)(info->direction - chosen_direction);
  1562.     
  1563.     // Decide whether to turn, or possibly shoot
  1564.     if      (correction < -9) setkey(keys, KEY_turnright);
  1565.     else if (correction >  9) setkey(keys, KEY_turnleft);
  1566.     else if (correction < -1) setkey(taps, KEY_turnright);
  1567.     else if (correction >  1) setkey(taps, KEY_turnleft);
  1568.     else if (shootit && info->gunrange == chosen_gunrange)
  1569.         {        // OK, we are on target, and we want to shoot
  1570.         shootsoon = TRUE;
  1571.         // Check man either inside tank, or safely away from the shot
  1572.         if (info->man_status == 0 || man_clear_of_shot())
  1573.             {
  1574.             if (killmine)        // If clearing mine, do this:
  1575.                 {
  1576.                 // Want to make sure tank is not turning, adjusting range etc.
  1577.                 // to be sure we will hit the mine and not waste a shell
  1578.                 u_long testkeys = 1<<KEY_turnleft  | 1<<KEY_turnright
  1579.                                 | 1<<KEY_morerange | 1<<KEY_lessrange
  1580.                                 | 1<<KEY_shoot;
  1581.                 if ((testkeys & (last_keys | last_taps)) == 0)
  1582.                     {
  1583.                     // Tap shoot key, to fire ONE shot at the mine
  1584.                     setkey(taps, KEY_shoot);
  1585.                     shotminex = currentminex;
  1586.                     shotminey = currentminey;
  1587.                     shotminetime = TimeNow;
  1588.                     }
  1589.                 }
  1590.             else                // else shooting tank or pillbox; do this:
  1591.                 {
  1592.                 setkey(keys, KEY_shoot);
  1593.                 if (shootwhat == OBJECT_PILLBOX) desired_dist = 0x700;
  1594.                 else desired_dist = 0x400;
  1595.                 // Get slightly closer when shooting a tank, in case it tries to run away
  1596.                 }
  1597.             }
  1598.         }
  1599.  
  1600.     // 1. If tank facing in wrong direction by more than +/- 45 degrees,
  1601.     //    or if speed is too high, then slow down.
  1602.     //    Also, consider building road or bridge under the tank, if necessary
  1603.     if (correction < -32 || correction > 32 || info->speed > max_speed)
  1604.         {
  1605.         goslower = TRUE;
  1606.         // Decide whether we should be building or farming here
  1607.         if (s.dobuilding && CAN_DO_BUILDING && !shootsoon) decide_building(nearx,neary);
  1608.         }
  1609.     else
  1610.         {
  1611.         // 2. If tank is facing in roughly the right direction, consider
  1612.         //    speeding up or slowing down, according to distance to target
  1613.         MAP_X examinex = info->tankx + sin(info->direction) >> 8;
  1614.         MAP_Y examiney = info->tanky - cos(info->direction) >> 8;
  1615.         TERRAIN t = getmapcellM(examinex, examiney);
  1616.         if (!info->inboat && t == DEEPSEA) fullstop = TRUE;
  1617.         
  1618.         if (info->inboat) gofaster = TRUE;
  1619.         else
  1620.             {
  1621.             if (target_distance > desired_dist + (info->speed<<4)) gofaster = TRUE;
  1622.             if (target_distance < desired_dist + (info->speed<<3)) goslower = TRUE;
  1623.             }
  1624.  
  1625.         // 3. If tank is facing in the correct direction, and moving forwards,
  1626.         //    see if it would be helpful to build road or bridge in front of us
  1627.         if (correction > -8 && correction < 8 && (gofaster || panic))
  1628.             {
  1629.             // If we want to go, but we are obstructed, then shoot our way out
  1630.             if (info->tankobstructed && info->speed < 1) setkey(keys, KEY_shoot);
  1631.  
  1632.             if (s.dobuilding && CAN_DO_BUILDING && !shootsoon)
  1633.                 {
  1634.                 int closest = 1, farthest = 3;
  1635.                 if (info->speed < 0x18) { closest = 2; farthest = 4; }
  1636.                 for (i=closest; i<=farthest; i++)
  1637.                     {
  1638.                     examinex = info->tankx + sin(info->direction)*i >> 8;
  1639.                     examiney = info->tanky - cos(info->direction)*i >> 8;
  1640.                     if (decide_building(examinex,examiney)) break;
  1641.                     }
  1642.                 }
  1643.     
  1644.             // If not in offensive pillbox mode, just drop pillboxes behind the tank
  1645.             // Note: the info->shells thing is a hack to make sure we don't drop a
  1646.             // pillbox somewhere and then find we have blocked ourself in somewhere
  1647.             if (CAN_BUILD_PILLBOX && !s.ppoffensive && info->shells > 20)
  1648.                 {
  1649.                 examinex = info->tankx - sin(info->direction)*2 >> 8;
  1650.                 examiney = info->tanky + cos(info->direction)*2 >> 8;
  1651.                 t = raw_getmapcell(examinex, examiney);
  1652.                 if (!(t & TERRAIN_MINE) && can_build_pillbox[t & TERRAIN_MASK])
  1653.                     {
  1654.                     info->build->x = examinex;
  1655.                     info->build->y = examiney;
  1656.                     info->build->action = BUILDMODE_PBOX;
  1657.                     }
  1658.                 }
  1659.             }
  1660.         }
  1661.  
  1662.     // And act on that decision
  1663.     if (fullstop || killmine) setkey(keys, KEY_slower);
  1664.     else if (panic) setkey(keys, KEY_faster);
  1665.     else
  1666.         {
  1667.         if (gofaster) setkey(keys, KEY_faster);
  1668.         if (goslower) setkey(keys, KEY_slower);
  1669.         }
  1670.  
  1671.     // Be vandalistic when running away?
  1672.     if (runaway && s.laymines) setkey(keys, KEY_dropmine);
  1673.  
  1674.     // Decide whether to adjust gun range
  1675.     if      (info->gunrange > chosen_gunrange+2) setkey(keys, KEY_lessrange);
  1676.     else if (info->gunrange < chosen_gunrange-2) setkey(keys, KEY_morerange);
  1677.     else if (info->gunrange > chosen_gunrange  ) setkey(taps, KEY_lessrange);
  1678.     else if (info->gunrange < chosen_gunrange  ) setkey(taps, KEY_morerange);
  1679.     }
  1680.  
  1681. // ****************************************************************************
  1682.  
  1683. // Interface code to communicate with Bolo
  1684.  
  1685. local void brain_think(void)
  1686.     {
  1687.     long thinktime;
  1688.     int i;
  1689.     ObjectInfo *ob;
  1690.     
  1691.     // Map square tank is on now
  1692.     nearx = info->tankx >> 8;
  1693.     neary = info->tanky >> 8;
  1694.     
  1695.     // Map squares tank is touching
  1696.     tankleftx   = info->tankx - 0x80 >> 8;
  1697.     tankrightx  = info->tankx + 0x80 >> 8;
  1698.     tanktopy    = info->tanky - 0x80 >> 8;
  1699.     tankbottomy = info->tanky + 0x80 >> 8;
  1700.     
  1701.     // See if tank is dangerously close to a mine
  1702.     tank_close_to_mine =checkmineM(tankleftx,  tanktopy   ) ||
  1703.                         checkmineM(tankrightx, tanktopy   ) ||
  1704.                         checkmineM(tankleftx,  tankbottomy) ||
  1705.                         checkmineM(tankrightx, tankbottomy);
  1706.  
  1707.     if (info->newtank)
  1708.         {
  1709.         explain("");
  1710.         explain("New tank");
  1711.         for (i=0; i<info->max_players;   i++) reset_progress(&tankprogress[i], 0);
  1712.         for (i=0; i<info->max_pillboxes; i++) reset_progress(&pillprogress[i], 0);
  1713.         for (i=0; i<info->max_refbases;  i++) reset_progress(&baseprogress[i], 0);
  1714.         reset_progress(&manrescueprogress, 0);
  1715.         if (s.explore) setscout();
  1716.         still_on_boat  = TRUE;                    // Tank starts on boat
  1717.         land_direction = info->direction;
  1718.         // See if we picked up a pillbox at x,y which killed us
  1719.         if (pillpickup_x) { fatal_x = pillpickup_x; fatal_y = pillpickup_y; }
  1720.         }
  1721.     pillpickup_x = pillpickup_y = 0;
  1722.     
  1723.     if (getmapcellM(nearx, neary) == DEEPSEA) { fatal_x = nearx; fatal_y = neary; }
  1724.     
  1725.     if (!info->inboat) still_on_boat = FALSE;    // Tank not on boat any more
  1726.  
  1727.     last_keys = keys;
  1728.     last_taps = taps;
  1729.     keys = taps = 0;
  1730.     shootit = shootsoon = runaway = FALSE;
  1731.     shootwhat = SHOOT_NOTHING;
  1732.     chosen_gunrange = MAXRANGE;
  1733.  
  1734.     // Count all shells, and count how many are coming towards us.
  1735.     incoming_shells = flying_shells = 0;
  1736.     for (ob=&info->objects[0]; ob<&info->objects[info->num_objects]; ob++)
  1737.         if (ob->object == OBJECT_SHOT)
  1738.             {
  1739.             char dev = ob->direction - aim( (long)info->tankx - (long)ob->x,
  1740.                                             (long)info->tanky - (long)ob->y );
  1741.             if (dev > -32 && dev < 32) incoming_shells++;
  1742.             flying_shells++;
  1743.             }
  1744.     
  1745.     for (i=0; i<16; i++)
  1746.         {
  1747.         direction_votes[i] = 0;
  1748.         target_distances[i] = 0xFFFFFFFF;
  1749.         direction_maxspeeds[i] = 0xFF;
  1750.         }
  1751.  
  1752.     cast_votes();
  1753.     count_votes();
  1754.  
  1755.     *(info->holdkeys) = keys;
  1756.     *(info->tapkeys ) = taps;
  1757.     
  1758.     thinktime = TickCount() - TimeNow;
  1759.     if (thinktime > 30)
  1760.         {
  1761.         explain("Warning: thought took %ld ticks", thinktime);
  1762.         if (do_explain) SysBeep(10);
  1763.         }
  1764.     }
  1765.  
  1766. local void set_brain_menu(short majormode)
  1767.     {
  1768.     CheckItem(MyMenu, m_default,    (majormode == m_default   ));
  1769.     CheckItem(MyMenu, m_assassin,   (majormode == m_assassin  ));
  1770.     CheckItem(MyMenu, m_pillhunter, (majormode == m_pillhunter));
  1771.     CheckItem(MyMenu, m_basehunter, (majormode == m_basehunter));
  1772.     CheckItem(MyMenu, m_defensive,  (majormode == m_defensive ));
  1773.     
  1774.     CheckItem(MyMenu, m_explore,      s.explore     );
  1775.     CheckItem(MyMenu, m_laymines,     s.laymines    );
  1776.     CheckItem(MyMenu, m_clearmines,   s.clearmines  );
  1777.     CheckItem(MyMenu, m_dobuilding,   s.dobuilding  );
  1778.     CheckItem(MyMenu, m_attacktanks,  s.attacktanks );
  1779.     CheckItem(MyMenu, m_attackpills,  s.attackpills );
  1780.     CheckItem(MyMenu, m_attackbases,  s.attackbases );
  1781.     CheckItem(MyMenu, m_repairpills,  s.repairpills );
  1782.     CheckItem(MyMenu, m_placepills,   s.placepills  );
  1783.     CheckItem(MyMenu, m_ppoffensive,  s.ppoffensive );
  1784.  
  1785.     CheckItem(MyMenu, m_explain,      do_explain    );
  1786.     CheckItem(MyMenu, m_route,        do_showroute  );
  1787.     }
  1788.  
  1789. local short brain_menu(short item)
  1790.     {
  1791.     switch (item)
  1792.         {
  1793.         case m_about      : Alert(1000, NULL); return(0);
  1794.         
  1795.         case m_default    : s = s_default;    break;
  1796.         case m_assassin   : s = s_assassin;   break;
  1797.         case m_pillhunter : s = s_pillhunter; break;
  1798.         case m_basehunter : s = s_basehunter; break;
  1799.         case m_defensive  : s = s_defensive;  break;
  1800.         
  1801.         case m_explore    : s.explore      ^= 1; break;
  1802.         case m_laymines   : s.laymines     ^= 1; break;
  1803.         case m_clearmines : s.clearmines   ^= 1; break;
  1804.         case m_dobuilding : s.dobuilding   ^= 1; break;
  1805.         case m_attacktanks: s.attacktanks  ^= 1; break;
  1806.         case m_attackpills: s.attackpills  ^= 1; break;
  1807.         case m_attackbases: s.attackbases  ^= 1; break;
  1808.         case m_repairpills: s.repairpills  ^= 1; break;
  1809.         case m_placepills : s.placepills   ^= 1; break;
  1810.         case m_ppoffensive: s.ppoffensive  ^= 1; break;
  1811.         
  1812.         case m_explain    : do_explain     ^= 1;
  1813.                             if (do_explain) ShowWindow(debugwindow);
  1814.                             else HideWindow(debugwindow);
  1815.                             break;
  1816.         
  1817.         case m_route      : do_showroute   ^= 1;
  1818.                             if (do_showroute) ShowWindow(routewindow);
  1819.                             else HideWindow(routewindow);
  1820.                             break;
  1821.         
  1822.         default: return(-1);
  1823.         }
  1824.     set_brain_menu(item);
  1825.     return(0);
  1826.     }
  1827.  
  1828. local Boolean brain_open(void)
  1829.     {
  1830.     static Rect debugrect = { 40, 4, 340, 200 };
  1831.     static Rect routerect = { 40, 220, 40+COST_ARRAY_SIZE*8, 220+COST_ARRAY_SIZE*8 };
  1832.     Boolean ok;
  1833.     tankprogress = (ProgressInfo *)NewPtr(sizeof(ProgressInfo) * info->max_players);
  1834.     pillprogress = (ProgressInfo *)NewPtr(sizeof(ProgressInfo) * info->max_pillboxes);
  1835.     baseprogress = (ProgressInfo *)NewPtr(sizeof(ProgressInfo) * info->max_refbases);
  1836.  
  1837.     MyMenu = GetMenu(MyMenuID);
  1838.     InsertMenu(MyMenu, 0);
  1839.     s = s_default;
  1840.     set_brain_menu(m_default);
  1841.     DrawMenuBar();
  1842.     
  1843.     debugwindow = NewWindow(NULL, &debugrect, info->playernames[info->player_number]->c,
  1844.                                 FALSE, documentProc, (WindowPtr)(-1), FALSE, 0);
  1845.     
  1846.     routewindow = NewCWindow(NULL, &routerect, info->playernames[info->player_number]->c,
  1847.                                 FALSE, documentProc, (WindowPtr)(-1), FALSE, 0);
  1848.     
  1849.     ok = tankprogress && pillprogress && baseprogress && debugwindow && routewindow;
  1850.  
  1851.     if (ok)
  1852.         {
  1853.         SysEnvRec sysenvirons;
  1854.         SysEnvirons(1, &sysenvirons);
  1855.         if (!sysenvirons.hasColorQD) { do_showroute = FALSE; DisableItem(MyMenu, m_route); }
  1856.         if (do_explain  ) ShowWindow(debugwindow);
  1857.         if (do_showroute) ShowWindow(routewindow);
  1858.         }
  1859.     return(ok);
  1860.     }
  1861.  
  1862. local void brain_close(void)
  1863.     {
  1864.     if (tankprogress) { DisposPtr((Ptr)tankprogress); tankprogress = NULL; }
  1865.     if (pillprogress) { DisposPtr((Ptr)pillprogress); pillprogress = NULL; }
  1866.     if (baseprogress) { DisposPtr((Ptr)baseprogress); baseprogress = NULL; }
  1867.     if (debugwindow)  { DisposeWindow(debugwindow);   debugwindow  = NULL; } 
  1868.     if (routewindow)  { DisposeWindow(routewindow);   routewindow  = NULL; }
  1869.     DeleteMenu(MyMenuID);
  1870.     ReleaseResource((Handle)MyMenu);
  1871.     DrawMenuBar();
  1872.     }
  1873.  
  1874. // If the Brain is being compiled as an application (ie with BrainFrame) instead
  1875. // of as a standalone code resource (a BBRN) then the symbol "main" is redefined
  1876. // as a subroutine for the BrainFrame to call.
  1877. #if !__option(a4_globals)
  1878. #define main BrainMain
  1879. BoloBrain BrainMain;
  1880. #endif
  1881.  
  1882. pascal short main(const BrainInfo *braininfo)
  1883.     {
  1884.     if (braininfo->InfoVersion != CURRENT_BRAININFO_VERSION) return(-1);
  1885.  
  1886.     info = braininfo;            // copy parameter into global variable
  1887.     TimeNow = TickCount();        // so we know how long we have been in this call
  1888.  
  1889.     switch (info->operation)
  1890.         {
  1891.         case BRAIN_OPEN  :    if (brain_open()) return(0);
  1892.                             else { brain_close(); return(-1); }
  1893.         case BRAIN_CLOSE :    brain_close(); return(0);
  1894.         case BRAIN_THINK :    brain_think(); return(0);
  1895.         case MyMenuID    :  return(brain_menu(info->menu_item));
  1896.         default          :  return(-1);
  1897.         }
  1898.     }
  1899.