home *** CD-ROM | disk | FTP | other *** search
/ Amiga Times / AmigaTimes.iso / spiele / FreeCiv / src / freeciv-1.7.0 / server / gotohand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-06  |  24.2 KB  |  707 lines

  1. /********************************************************************** 
  2.  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2, or (at your option)
  6.    any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12. ***********************************************************************/
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <assert.h>
  16. #include <string.h>
  17.  
  18. #include <map.h>
  19. #include <game.h>
  20. #include <unitfunc.h>
  21. #include <unithand.h>
  22. #include <unittools.h>
  23. #include <gotohand.h>
  24. #include <settlers.h>
  25.  
  26. struct move_cost_map warmap;
  27.  
  28. struct stack_element {
  29.   unsigned char x, y;
  30. } warstack[MAP_MAX_WIDTH * MAP_MAX_HEIGHT];
  31.  
  32. /* this wastes ~20K of memory and should really be fixed but I'm lazy  -- Syela */
  33.  
  34. int warstacksize;
  35. int warnodes;
  36.  
  37. void add_to_stack(int x, int y)
  38. {
  39.   warstack[warstacksize].x = x;
  40.   warstack[warstacksize].y = y;
  41.   warstacksize++;
  42. }
  43.  
  44. void init_warmap(int orig_x, int orig_y, enum unit_move_type which)
  45. {
  46.   int x, y, i, j;
  47.   int maxcost = THRESHOLD * 6 + 2; /* should be big enough without being TOO big */
  48.   for (x = 0; x < map.xsize; x++) {
  49.     if (x > orig_x)
  50.       i = MIN(x - orig_x, orig_x + map.xsize - x);
  51.     else
  52.       i = MIN(orig_x - x, x + map.xsize - orig_x);      
  53.     for (y = 0; y < map.ysize; y++) {
  54.       if (y > orig_y)
  55.         j = MAX(y - orig_y, i);
  56.       else
  57.         j = MAX(orig_y - y, i);
  58.       j *= 3;
  59.       if (j < maxcost) j = maxcost;
  60.       if (j > 255) j = 255;
  61.       if (which == LAND_MOVING) warmap.cost[x][y] = j; /* one if by land */
  62.       else warmap.seacost[x][y] = j;
  63.     }
  64.   }
  65.   if (which == LAND_MOVING) warmap.cost[orig_x][orig_y] = 0;
  66.   else warmap.seacost[orig_x][orig_y] = 0;
  67. }  
  68.  
  69. void really_generate_warmap(struct city *pcity, struct unit *punit, enum unit_move_type which)
  70. { /* let generate_warmap interface to this function */
  71.   int x, y, c, i, j, k, xx[3], yy[3], tm;
  72.   int orig_x, orig_y;
  73.   int igter = 0;
  74.   int ii[8] = { 0, 1, 2, 0, 2, 0, 1, 2 };
  75.   int jj[8] = { 0, 0, 0, 1, 1, 2, 2, 2 };
  76.   int maxcost = THRESHOLD * 6 + 2; /* should be big enough without being TOO big */
  77.   struct tile *tile0;
  78.   struct player *pplayer;
  79.  
  80.   if (pcity) {
  81.     orig_x = pcity->x;
  82.     orig_y = pcity->y;
  83.     pplayer = &game.players[pcity->owner];
  84.   } else {
  85.     orig_x = punit->x;
  86.     orig_y = punit->y;
  87.     pplayer = &game.players[punit->owner];
  88.   }
  89.  
  90.   init_warmap(orig_x, orig_y, which);
  91.   warstacksize = 0;
  92.   warnodes = 0;
  93.  
  94.   add_to_stack(orig_x, orig_y);
  95.  
  96.   if (punit && unit_flag(punit->type, F_IGTER)) igter++;
  97.   if (punit && punit->type == U_SETTLERS) maxcost >>= 1;
  98.  
  99.   do {
  100.     x = warstack[warnodes].x;
  101.     y = warstack[warnodes].y;
  102.     warnodes++; /* for debug purposes */
  103.     tile0 = map_get_tile(x, y);
  104.     if((xx[2]=x+1)==map.xsize) xx[2]=0;
  105.     if((xx[0]=x-1)==-1) xx[0]=map.xsize-1;
  106.     xx[1] = x;
  107.     if ((yy[0]=y-1)==-1) yy[0] = 0;
  108.     if ((yy[2]=y+1)==map.ysize) yy[2]=y;
  109.     yy[1] = y;
  110.     for (k = 0; k < 8; k++) {
  111.       i = ii[k]; j = jj[k]; /* saves CPU cycles? */
  112.       if (which == LAND_MOVING) {
  113. /*        if (tile0->move_cost[k] == -3 || tile0->move_cost[k] > 16) c = maxcost;*/
  114.         if (map_get_terrain(xx[i], yy[j]) == T_OCEAN) {
  115.           if (punit && is_transporter_with_free_space(pplayer, xx[i], yy[j])) c = 3;
  116.           else c = maxcost;
  117.         } else if (tile0->terrain == T_OCEAN) c = 3;
  118.         else if (igter) c = 3; /* NOT c = 1 */
  119.         else if (punit) c = MIN(tile0->move_cost[k], unit_types[punit->type].move_rate);
  120. /*        else c = tile0->move_cost[k]; 
  121. This led to a bad bug where a unit in a swamp was considered too far away */
  122.         else {
  123.           tm = map_get_tile(xx[i], yy[j])->move_cost[7-k];
  124.           c = (tile0->move_cost[k] + tm + (tile0->move_cost[k] > tm ? 1 : 0))>>1;
  125.         }
  126.         
  127.         tm = warmap.cost[x][y] + c;
  128.         if (warmap.cost[xx[i]][yy[j]] > tm && tm < maxcost) {
  129.           warmap.cost[xx[i]][yy[j]] = tm;
  130.           add_to_stack(xx[i], yy[j]);
  131.         }
  132.       } else {
  133.         c = 3; /* allow for shore bombardment/transport/etc */
  134.         tm = warmap.seacost[x][y] + c;
  135.         if (warmap.seacost[xx[i]][yy[j]] > tm && tm < maxcost) {
  136.           warmap.seacost[xx[i]][yy[j]] = tm;
  137.           if (tile0->move_cost[k] == -3) add_to_stack(xx[i], yy[j]);
  138.         }
  139.       }
  140.     } /* end for */
  141.   } while (warstacksize > warnodes);
  142.   if (warnodes > 15000) printf("Warning: %d nodes in map #%d for (%d, %d)\n",
  143.      warnodes, which, orig_x, orig_y);
  144. /* printf("Generated warmap for (%d,%d) with %d nodes checked.\n", orig_x, orig_y, warnodes); */
  145. /* warnodes is often as much as 2x the size of the continent -- Syela */
  146. }
  147.  
  148. void generate_warmap(struct city *pcity, struct unit *punit)
  149. {
  150. /*printf("Generating warmap, pcity = %s, punit = %s\n", (pcity ?
  151. pcity->name : "NULL"), (punit ? unit_types[punit->type].name : "NULL"));*/
  152.  
  153.   if (punit) {
  154.     if (pcity && pcity == warmap.warcity) return; /* time-saving shortcut */
  155.     if (warmap.warunit == punit && !warmap.cost[punit->x][punit->y]) return;
  156.     pcity = 0;
  157.   }
  158.  
  159.   warmap.warcity = pcity;
  160.   warmap.warunit = punit;
  161.  
  162.   if (punit) {
  163.     if (is_sailing_unit(punit)) {
  164.       init_warmap(punit->x, punit->y, LAND_MOVING);
  165.       really_generate_warmap(pcity, punit, SEA_MOVING);
  166.     } else {
  167.       init_warmap(punit->x, punit->y, SEA_MOVING);
  168.       really_generate_warmap(pcity, punit, LAND_MOVING);
  169.     }
  170.     warmap.orig_x = punit->x;
  171.     warmap.orig_y = punit->y;
  172.   } else {
  173.     really_generate_warmap(pcity, punit, LAND_MOVING);
  174.     really_generate_warmap(pcity, punit, SEA_MOVING);
  175.     warmap.orig_x = pcity->x;
  176.     warmap.orig_y = pcity->y;
  177.   }
  178. }
  179.  
  180. /* ....... end of old advmilitary.c, beginning of old gotohand.c. ..... */
  181.  
  182. int could_unit_move_to_tile(struct unit *punit, int x0, int y0, int x, int y)
  183. { /* this WAS can_unit_move_to_tile with the notifys removed -- Syela */
  184. /* but is now a little more complicated to allow non-adjacent tiles */
  185.   struct tile *ptile,*ptile2;
  186.   struct city *pcity;
  187.  
  188.   if(punit->activity!=ACTIVITY_IDLE && punit->activity!=ACTIVITY_GOTO)
  189.     return 0;
  190.   
  191.   if(x<0 || x>=map.xsize || y<0 || y>=map.ysize)
  192.     return 0;
  193.   
  194.   if(!is_tiles_adjacent(x0, y0, x, y))
  195.     return 0; 
  196.  
  197.   if(is_enemy_unit_tile(x,y,punit->owner))
  198.     return 0;
  199.  
  200.   ptile=map_get_tile(x, y);
  201.   ptile2=map_get_tile(x0, y0);
  202.   if(is_ground_unit(punit)) {
  203.     /* Check condition 4 */
  204.     if(ptile->terrain==T_OCEAN &&
  205.        !is_transporter_with_free_space(&game.players[punit->owner], x, y))
  206.     return 0;
  207.  
  208.     /* Moving from ocean */
  209.     if(ptile2->terrain==T_OCEAN) {
  210.       /* Can't attack a city from ocean unless marines */
  211.       if(!unit_flag(punit->type, F_MARINES) && is_enemy_city_tile(x,y,punit->owner)) {
  212.     return 0;
  213.       }
  214.     }
  215.   } else if(is_sailing_unit(punit)) {
  216.     if(ptile->terrain!=T_OCEAN && ptile->terrain!=T_UNKNOWN)
  217.       if(!is_friendly_city_tile(x,y,punit->owner))
  218.     return 0;
  219.   } 
  220.  
  221.   if((pcity=map_get_city(x, y))) {
  222.     if ((pcity->owner!=punit->owner && (is_air_unit(punit) || 
  223.                                         !is_military_unit(punit)))) {
  224.         return 0;  
  225.     }
  226.   }
  227.  
  228. /*  zoc = zoc_ok_move(punit, x, y);      can't use this, so reproducing ... */
  229.   /* if you have units there, you can move */
  230.   if (is_friendly_unit_tile(x,y,punit->owner))
  231.     return 1;
  232.   if (!is_ground_unit(punit) || unit_flag(punit->type, F_IGZOC))
  233.     return 1;
  234.   if (map_get_city(x,y) || map_get_city(x0, y0))
  235.     return 1;
  236.   return (is_my_zoc(punit, x0, y0) || is_my_zoc(punit, x, y));
  237. }
  238.  
  239. int goto_tile_cost(struct player *pplayer, struct unit *punit, int x0, int y0, int x1, int y1, int m)
  240. {
  241.   if (!pplayer->ai.control && !map_get_known(x1, y1, pplayer)) {
  242. /*    printf("Venturing into the unknown at (%d, %d).\n", x1, y1);*/
  243. /*    return(3);   People seemed not to like this. -- Syela */
  244.     return(15); /* arbitrary deterrent. */
  245.   }
  246.   if (get_defender(pplayer, punit, x1, y1)) {
  247.      if (same_pos(punit->goto_dest_x, punit->goto_dest_y, x1, y1))
  248.        return(MIN(m, unit_types[punit->type].move_rate));
  249.      if (!can_unit_attack_tile(punit, x1, y1)) return(255);
  250.      return(15);
  251. /* arbitrary deterrent; if we wanted to attack, we wouldn't GOTO */
  252.   } else {
  253.     if (!could_unit_move_to_tile(punit, x0, y0, x1, y1) &&
  254.         !same_pos(x1, y1, punit->goto_dest_x, punit->goto_dest_y)) return(255);
  255. /* in order to allow transports to GOTO shore correctly */
  256.   }
  257.   return(MIN(m, unit_types[punit->type].move_rate));
  258. }
  259.  
  260. void init_gotomap(int orig_x, int orig_y)
  261. {
  262.   int x, y;
  263.   for (x = 0; x < map.xsize; x++) {
  264.     for (y = 0; y < map.ysize; y++) {
  265.       warmap.seacost[x][y] = 255;
  266.       warmap.cost[x][y] = 255;
  267.       warmap.vector[x][y] = 0;
  268.     }
  269.   }
  270.   warmap.cost[orig_x][orig_y] = 0;
  271.   warmap.seacost[orig_x][orig_y] = 0;
  272.   return;
  273.  
  274. int dir_ok(int x0, int y0, int x1, int y1, int k)
  275. { /* The idea of this is to check less nodes in the wrong direction.
  276. These if's might cost some CPU but hopefully less overall. -- Syela */
  277.   int n = 0, s = 0, e = 0, w = 0, dx;
  278.   if (y1 > y0) s = y1 - y0;
  279.   else n = y0 - y1;
  280.   dx = x1 - x0;
  281.   if (dx > map.xsize>>1) w = map.xsize - dx;
  282.   else if (dx > 0) e = dx;
  283.   else if (dx + (map.xsize>>1) > 0) w = 0 - dx;
  284.   else e = map.xsize + dx;
  285.   if (e == map.xsize / 2 || w == map.xsize / 2) { /* thanks, Massimo */
  286.     if (k < 3 && s >= MAX(e, w)) return 0;
  287.     if (k > 4 && n >= MAX(e, w)) return 0;
  288.     return 1;
  289.   }
  290.   switch(k) {
  291.     case 0:
  292.       if (e >= n && s >= w) return 0;
  293.       else return 1;
  294.     case 1:
  295.       if (s && s >= e && s >= w) return 0;
  296.       else return 1;
  297.     case 2:
  298.       if (w >= n && s >= e) return 0;
  299.       else return 1;
  300.     case 3:
  301.       if (e && e >= n && e >= s) return 0;
  302.       else return 1;
  303.     case 4:
  304.       if (w && w >= n && w >= s) return 0;
  305.       else return 1;
  306.     case 5:
  307.       if (e >= s && n >= w) return 0;
  308.       else return 1;
  309.     case 6:
  310.       if (n && n >= w && n >= e) return 0;
  311.       else return 1;
  312.     case 7:
  313.       if (w >= s && n >= e) return 0;
  314.       else return 1;
  315.     default:
  316.       printf("Bad dir_ok call: (%d, %d) -> (%d, %d), %d\n", x0, y0, x1, y1, k);
  317.       return 0;
  318.   }
  319. }
  320.  
  321. int dir_ect(int x0, int y0, int x1, int y1, int k)
  322. {
  323.   int ii[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
  324.   int jj[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
  325.   int x, y;
  326.   x = map_adjust_x(ii[k] + x0);
  327.   y = jj[k] + y0; /* trusted, since I know who's calling us. -- Syela */
  328.   if (same_pos(x, y, x1, y1)) return 1; /* as direct as it gets! */
  329.   return (1 - dir_ok(x, y, x1, y1, 7-k));
  330. }
  331.  
  332. int find_the_shortest_path(struct player *pplayer, struct unit *punit,
  333.                            int dest_x, int dest_y)
  334. {
  335. /*  char *d[] = { "NW", "N", "NE", "W", "E", "SW", "S", "SE" };*/
  336.   int ii[8] = { 0, 1, 2, 0, 2, 0, 1, 2 };
  337.   int jj[8] = { 0, 0, 0, 1, 1, 2, 2, 2 };
  338.   int igter = 0, xx[3], yy[3], x, y, i, j, k, tm, c;
  339.   int orig_x, orig_y;
  340.   struct tile *tile0;
  341.   enum unit_move_type which = unit_types[punit->type].move_type;
  342.   int maxcost = 255;
  343.   unsigned char local_vector[MAP_MAX_WIDTH][MAP_MAX_HEIGHT];
  344.   struct unit *passenger; /* and I ride and I ride */
  345.   
  346. /* Often we'll already have a working warmap, but I don't want to
  347. deal with merging these functions yet.  Once they work correctly
  348. and independently I can worry about optimizing them. -- Syela */
  349.  
  350.   memset(local_vector, 0, sizeof(local_vector));
  351. /* I think I only need to zero (orig_x, orig_y), but ... */
  352.  
  353.   init_gotomap(punit->x, punit->y);
  354.   warstacksize = 0;
  355.   warnodes = 0;
  356.  
  357.   orig_x = punit->x;
  358.   orig_y = punit->y;
  359.  
  360.   add_to_stack(orig_x, orig_y);
  361.  
  362.   if (punit && unit_flag(punit->type, F_IGTER)) igter++;
  363.   if (which == SEA_MOVING) passenger = other_passengers(punit);
  364.   else passenger = 0;
  365.  
  366.   if (passenger)
  367.     if (map_get_terrain(dest_x, dest_y) == T_OCEAN ||
  368.           is_friendly_unit_tile(dest_x, dest_y, passenger->owner) ||
  369.           is_friendly_city_tile(dest_x, dest_y, passenger->owner) ||
  370.           unit_flag(passenger->type, F_MARINES) ||
  371.           is_my_zoc(passenger, dest_x, dest_y)) passenger = 0;
  372.  
  373. /* if passenger is nonzero, the next-to-last tile had better be zoc-ok! */
  374.  
  375.   do {
  376.     x = warstack[warnodes].x;
  377.     y = warstack[warnodes].y;
  378.     warnodes++; /* for debug purposes */
  379.     tile0 = map_get_tile(x, y);
  380.     if((xx[2]=x+1)==map.xsize) xx[2]=0;
  381.     if((xx[0]=x-1)==-1) xx[0]=map.xsize-1;
  382.     xx[1] = x;
  383.     if ((yy[0]=y-1)==-1) yy[0] = 0;
  384.     if ((yy[2]=y+1)==map.ysize) yy[2]=y;
  385.     yy[1] = y;
  386.     
  387.     for (k = 0; k < 8; k++) {
  388.       i = ii[k]; j = jj[k]; /* saves CPU cycles? */
  389.       if (which != SEA_MOVING) {
  390.         if (which != LAND_MOVING) c = 3;
  391.         else if (tile0->move_cost[k] == -3 || tile0->move_cost[k] > 16) c = maxcost; 
  392.         else if (igter) c = (tile0->move_cost[k] ? 3 : 0); /* Reinier's fix -- Syela */
  393.         else c = tile0->move_cost[k];
  394.         c = goto_tile_cost(pplayer, punit, x, y, xx[i], yy[j], c);
  395.         if (!dir_ok(x, y, dest_x, dest_y, k)) c += c;
  396.         if (!c && !dir_ect(x, y, dest_x, dest_y, k)) c = 1;
  397.         tm = warmap.cost[x][y] + c;
  398. #ifdef ACTUALLYTESTED
  399.         if (warmap.cost[x][y] < punit->moves_left && tm < maxcost &&
  400.             tm >= punit->moves_left - MIN(3, c) && enemies_at(punit, xx[i], yy[j])) {
  401.           tm += unit_types[punit->type].move_rate;
  402. /*printf("%s#%d@(%d,%d) dissuaded from (%d,%d) -> (%d,%d)\n",
  403. unit_types[punit->type].name, punit->id, punit->x, punit->y, xx[i], yy[j],
  404. punit->goto_dest_x, punit->goto_dest_y);*/
  405.         }
  406. #endif
  407.         if (tm < maxcost) {
  408.           if (warmap.cost[xx[i]][yy[j]] > tm) {
  409.             warmap.cost[xx[i]][yy[j]] = tm;
  410.             add_to_stack(xx[i], yy[j]);
  411.             local_vector[xx[i]][yy[j]] = 128>>k;
  412. /*printf("Candidate: %s from (%d, %d) to (%d, %d) +%d to %d\n", d[k], x, y, xx[i], yy[j], c, tm);*/
  413.           } else if (warmap.cost[xx[i]][yy[j]] == tm) {
  414.             local_vector[xx[i]][yy[j]] |= 128>>k;
  415. /*printf("Co-Candidate: %s from (%d, %d) to (%d, %d) +%d to %d\n", d[k], x, y, xx[i], yy[j], c, tm);*/
  416.           }
  417.         }
  418.       } else {
  419.         if (tile0->move_cost[k] != -3) c = maxcost;
  420.         else if (punit->type == U_TRIREME && !is_coastline(xx[i], yy[j])) c = 7;
  421.         else c = 3;
  422. /* I want to disable these totally but for some reason it bugs. -- Syela */
  423.         c = goto_tile_cost(pplayer, punit, x, y, xx[i], yy[j], c);
  424.         if (xx[i] == dest_x && yy[j] == dest_y && passenger && c < 60 &&
  425.             !is_my_zoc(passenger, x, y)) c = 60; /* passenger cannot disembark */
  426.         if (!dir_ok(x, y, dest_x, dest_y, k)) c += c;
  427.         tm = warmap.seacost[x][y] + c;
  428.         if (warmap.seacost[x][y] < punit->moves_left && tm < maxcost &&
  429.             tm >= punit->moves_left - 3 && enemies_at(punit, xx[i], yy[j])) {
  430.           tm += unit_types[punit->type].move_rate;
  431. /*printf("%s#%d@(%d,%d) dissuaded from (%d,%d) -> (%d,%d)\n",
  432. unit_types[punit->type].name, punit->id, punit->x, punit->y, xx[i], yy[j],
  433. punit->goto_dest_x, punit->goto_dest_y);*/
  434.         }
  435.         if (tm < maxcost) {
  436.           if (warmap.seacost[xx[i]][yy[j]] > tm) {
  437.             warmap.seacost[xx[i]][yy[j]] = tm;
  438.             add_to_stack(xx[i], yy[j]);
  439.             local_vector[xx[i]][yy[j]] = 128>>k;
  440.           } else if (warmap.seacost[xx[i]][yy[j]] == tm) {
  441.             local_vector[xx[i]][yy[j]] |= 128>>k;
  442.           }
  443.         }
  444.       }
  445.       if (xx[i] == dest_x && yy[j] == dest_y && maxcost > tm) {
  446. /*printf("Found path, cost = %d\n", tm);*/
  447.         maxcost = tm + 1; /* NOT = tm.  Duh! -- Syela */
  448.       }
  449.     } /* end for */
  450.   } while (warstacksize > warnodes);
  451. /*printf("GOTO: (%d, %d) -> (%d, %d), %d nodes, cost = %d\n", 
  452. orig_x, orig_y, dest_x, dest_y, warnodes, maxcost - 1);*/
  453.   if (maxcost == 255) return(0);
  454. /* succeeded.  the vector at the destination indicates which way we get there */
  455. /* backtracing */
  456.   warnodes = 0;
  457.   warstacksize = 0;
  458.   add_to_stack(dest_x, dest_y);
  459.  
  460.   do {
  461.     x = warstack[warnodes].x;
  462.     y = warstack[warnodes].y;
  463.     warnodes++; /* for debug purposes */
  464.     tile0 = map_get_tile(x, y);
  465.     if((xx[2]=x+1)==map.xsize) xx[2]=0;
  466.     if((xx[0]=x-1)==-1) xx[0]=map.xsize-1;
  467.     xx[1] = x;
  468.     if ((yy[0]=y-1)==-1) yy[0] = 0;
  469.     if ((yy[2]=y+1)==map.ysize) yy[2]=y;
  470.     yy[1] = y;
  471.  
  472.     for (k = 0; k < 8; k++) {
  473.       i = ii[k]; j = jj[k]; /* saves CPU cycles? */
  474.       if (local_vector[x][y] & (1<<k)) {
  475. /* && (local_vector[xx[i]][yy[j]] || !warmap.vector[xx[i]][yy[j]])) {
  476. is not adequate to prevent RR loops.  Bummer. -- Syela */
  477.         add_to_stack(xx[i], yy[j]);
  478.         warmap.vector[xx[i]][yy[j]] |= 128>>k;
  479.         local_vector[x][y] -= 1<<k; /* avoid repetition */
  480. /*printf("PATH-SEGMENT: %s from (%d, %d) to (%d, %d)\n", d[7-k], xx[i], yy[j], x, y);*/
  481.       }
  482.     }
  483.   } while (warstacksize > warnodes);
  484. /*printf("BACKTRACE: %d nodes\n", warnodes);*/
  485.   return(1);
  486. /* DONE! */
  487. }
  488.  
  489. int find_a_direction(struct unit *punit)
  490. {
  491.   int k, d[8], x, y, n, a, best = 0, d0, d1, h0, h1, u, c;
  492.   int ii[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
  493.   int jj[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
  494.   struct tile *ptile, *adjtile;
  495.   int nearland;
  496.   struct city *pcity;
  497.   struct unit *passenger;
  498.  
  499.   if (map_get_terrain(punit->x, punit->y) == T_OCEAN)
  500.     passenger = other_passengers(punit);
  501.   else passenger = 0;
  502.  
  503.   for (k = 0; k < 8; k++) {
  504.     if (!(warmap.vector[punit->x][punit->y]&(1<<k))) d[k] = 0;
  505.     else {
  506.       if (is_ground_unit(punit))
  507.         c = map_get_tile(punit->x, punit->y)->move_cost[k];
  508.       else c = 3;
  509.       if (unit_flag(punit->type, F_IGTER) && c) c = 1;
  510.       x = map_adjust_x(punit->x + ii[k]); y = map_adjust_y(punit->y + jj[k]);
  511. /*if (passenger) printf("%d@(%d,%d) evaluating (%d,%d)[%d/%d]\n",
  512. punit->id, punit->x, punit->y, x, y, c, punit->moves_left);*/
  513.       ptile = map_get_tile(x, y);
  514.       d0 = get_virtual_defense_power(U_HOWITZER, punit->type, x, y);
  515.       pcity = map_get_city(x, y);
  516.       n = 2;
  517.       if (pcity) { /* this code block inspired by David Pfitzner -- Syela */
  518.         if (city_got_citywalls(pcity)) n += 2;
  519.         if (city_got_building(pcity, B_SDI)) n++;
  520.         if (city_got_building(pcity, B_SAM)) n++;
  521.         if (city_got_building(pcity, B_COASTAL)) n++;
  522.       }
  523.       d0 = (d0 * n) / 2;
  524.       h0 = punit->hp; h1 = 0; d1 = 0; u = 1;
  525.       unit_list_iterate(ptile->units, aunit)
  526.         if (aunit->owner != punit->owner) d1 = -1; /* MINIMUM priority */
  527.         else {
  528.           u++;
  529.           a = get_virtual_defense_power(U_HOWITZER, aunit->type, x, y) * n / 2;
  530.           if (a * aunit->hp > d1 * h1) { d1 = a; h1 = aunit->hp; }
  531.         }
  532.       unit_list_iterate_end;
  533.       if (u == 1) d[k] = d0 * h0;
  534.       else if (pcity || ptile->special&S_FORTRESS)
  535.         d[k] = MAX(d0 * h0, d1 * h1);
  536.       else if ((d0 * h0) <= (d1 * h1)) d[k] = (d1 * h1) * (u - 1) / u;
  537.       else d[k] = MIN(d0 * h0 * u, d0 * h0 * d0 * h0 * (u - 1) / MAX(u, (d1 * h1 * u)));
  538.       if (d0 > d1) d1 = d0;
  539.  
  540.       if (ptile->special&S_ROAD) d[k] += 10; /* in case we change directions */
  541.       if (ptile->special&S_RAILROAD) d[k] += 10; /* next turn, roads are nice */
  542.  
  543.       nearland = 0;
  544.       for (n = 0; n < 8; n++) {
  545.         adjtile = map_get_tile(x + ii[n], y + jj[n]);
  546.         if (adjtile->terrain != T_OCEAN) nearland++;
  547.         if (!((adjtile->known)&(1u<<punit->owner))) {
  548.           if (punit->moves_left <= c) d[k] -= (d[k]>>4); /* Avoid the unknown */
  549.           else d[k]++; /* nice but not important */
  550.         } else { /* NOTE: Not being omniscient here!! -- Syela */
  551.           unit_list_iterate(adjtile->units, aunit) /* lookin for trouble */
  552.             if (aunit->owner != punit->owner && (a = get_attack_power(aunit))) {
  553.               if (punit->moves_left < c + 3) { /* can't fight */
  554.                 if (passenger && !is_ground_unit(aunit)) d[k] = -99;
  555.                 else d[k] -= d1 * (aunit->hp * a * a / (a * a + d1 * d1));
  556.               }
  557.             }
  558.           unit_list_iterate_end;
  559.         } /* end this-tile-is-seen else */
  560.       } /* end tiles-adjacent-to-dest for */
  561.  
  562.       if (punit->type == U_TRIREME && !nearland) {
  563.         if (punit->moves_left < 6) d[k] = 1;
  564.         else if (punit->moves_left == 6) {
  565.           for (n = 0; n < 8; n++) {
  566.             if ((warmap.vector[x][y]&(1<<n))) {
  567.               if (is_coastline(x + ii[n], y + jj[n])) nearland++;
  568.             }
  569.           }
  570.           if (!nearland) d[k] = 1;
  571.         }
  572.       }
  573.  
  574.       if (d[k] < 1 && (!game.players[punit->owner].ai.control ||
  575.          !punit->ai.passenger || punit->moves_left >= 6)) d[k] = 1;
  576.       if (d[k] > best) { 
  577.         best = d[k];
  578. /*printf("New best = %d: (%d, %d) -> (%d, %d)\n", best, punit->x, punit->y, x, y);*/
  579.       }
  580.     } /* end is-a-valid-vector */
  581.   } /* end for */
  582.  
  583.   if (!best) {
  584.     return(-1);
  585.   }
  586.  
  587.   do {
  588.     k = myrand(8);
  589.   } while (d[k] < best);
  590.   return(k);
  591. }
  592.  
  593. int goto_is_sane(struct player *pplayer, struct unit *punit, int x, int y, int omni)
  594. {  
  595.   int ii[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
  596.   int jj[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
  597.   int k, possible = 0;
  598.   if (same_pos(punit->x, punit->y, x, y)) return 1;
  599.   if (is_ground_unit(punit) && 
  600.           (omni || map_get_known(x, y, pplayer))) {
  601.     if (map_get_terrain(x, y) == T_OCEAN) {
  602.       if (is_transporter_with_free_space(pplayer, x, y)) {
  603.         for (k = 0; k < 8; k++) {
  604.           if (map_get_continent(punit->x, punit->y) ==
  605.               map_get_continent(x + ii[k], y + jj[k]))
  606.             possible++;
  607.         }
  608.       }
  609.     } else { /* going to a land tile */
  610.       if (map_get_continent(punit->x, punit->y) ==
  611.             map_get_continent(x, y))
  612.          possible++;
  613.       else {
  614.         for (k = 0; k < 8; k++) {
  615.           if (map_get_continent(punit->x + ii[k], punit->y + jj[k]) ==
  616.               map_get_continent(x, y))
  617.             possible++;
  618.         }
  619.       }
  620.     }
  621.     return(possible);
  622.   } else if (is_sailing_unit(punit) && (omni || map_get_known(x, y, pplayer)) &&
  623.        map_get_terrain(x, y) != T_OCEAN && !map_get_tile(x, y)->city_id &&
  624.        !is_terrain_near_tile(x, y, T_OCEAN)) {
  625.     return(0);
  626.   } /* end pre-emption subroutine. */
  627.   return(1);
  628. }
  629.  
  630.  
  631. /**************************************************************************
  632. ...
  633. **************************************************************************/
  634. void do_unit_goto(struct player *pplayer, struct unit *punit)
  635. {
  636.   int x, y, k;
  637.   int ii[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
  638.   int jj[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
  639. /*  char *d[] = { "NW", "N", "NE", "W", "E", "SW", "S", "SE" };*/
  640.  
  641.   int id=punit->id;
  642.  
  643. /* there was a really oogy if here.  Mighty Mouse told me not to axe it
  644. because it would cost oodles of CPU time.  He's right for the most part
  645. but Peter and others have recommended more flexibility, so this is a little
  646. different but should still pre-empt calculation of impossible GOTO's. -- Syela */
  647.  
  648.   if (same_pos(punit->x, punit->y, punit->goto_dest_x, punit->goto_dest_y) ||
  649.       !goto_is_sane(pplayer, punit, punit->goto_dest_x, punit->goto_dest_y, 0)) {
  650.     punit->activity=ACTIVITY_IDLE;
  651.     send_unit_info(0, punit, 0);
  652.     return;
  653.   }
  654.  
  655.   punit->activity = ACTIVITY_GOTO; /* adding this as a failsafe -- Syela */
  656.  
  657.   if(!punit->moves_left) {
  658.     send_unit_info(0, punit, 0);
  659.     return;
  660.   }
  661.  
  662.   if(find_the_shortest_path(pplayer, punit, 
  663.                 punit->goto_dest_x, punit->goto_dest_y)) {
  664.  
  665.     do {
  666.       if(!punit->moves_left) return;
  667.       k = find_a_direction(punit);
  668.       if (k < 0) {
  669. printf("%s#%d@(%d,%d) stalling so it won't be killed.\n",
  670. unit_types[punit->type].name, punit->id, punit->x, punit->y);
  671. /*        punit->activity=ACTIVITY_IDLE;*/
  672.     send_unit_info(0, punit, 0);
  673.     return;
  674.       }
  675. /*printf("Going %s\n", d[k]);*/
  676.       x = map_adjust_x(punit->x + ii[k]);
  677.       y = punit->y + jj[k]; /* no need to adjust this */
  678.  
  679.       if(!punit->moves_left) return;
  680.       if(!handle_unit_move_request(pplayer, punit, x, y)) {
  681. /*printf("Couldn't handle it.\n");*/
  682.     if(punit->moves_left) {
  683.       punit->activity=ACTIVITY_IDLE;
  684.       send_unit_info(0, punit, 0);
  685.       return;
  686.     };
  687.       } /*else printf("Handled.\n");*/
  688.       if(!unit_list_find(&pplayer->units, id))
  689.     return; /* unit died during goto! */
  690.  
  691.       if(punit->x!=x || punit->y!=y) {
  692. /*printf("Aborting, out of movepoints.\n");*/
  693.     send_unit_info(0, punit, 0);
  694.     return; /* out of movepoints */
  695.       }
  696. /*printf("Moving on.\n");*/
  697.     } while(!(x==punit->goto_dest_x && y==punit->goto_dest_y));
  698.   }
  699. else printf("Did not find the shortest path for %s's %s at (%d, %d) -> (%d, %d)\n",
  700. pplayer->name, unit_types[punit->type].name, punit->x, punit->y, 
  701. punit->goto_dest_x, punit->goto_dest_y);
  702.  
  703.   punit->activity=ACTIVITY_IDLE;
  704.   send_unit_info(0, punit, 0);
  705. }
  706.