Complete.Org:
Mailing Lists:
Archives:
freeciv-dev:
September 2004: [Freeciv-Dev] (PR#7282) Patch: connect as orders |
![]() |
[Freeciv-Dev] (PR#7282) Patch: connect as orders[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=7282 > > [glip - Tue Aug 10 15:23:11 2004]: > > In the attached patch I: > > * extended PF by introducing a new callback get_costs, which does > everything: sets both MC and EC, checks if the tile is known, checks if > we found a better path. As a consequence it takes a whole lot of > arguments, but I still like it. > > * used this to tune the road connect. It now takes into account > - time to build road at the source tile > - movement bonus created after we've built a road > - many other little things. > As a result it prints the correct time. > > What hasn't been done: > * other types of connect > * ZoC is not taken into account > * there is a little bug when you just hit ctrl-shift-r, it shows 0 for > the tile you are on, even though it's not 0. If you move pointer to > another tile and then come back, it shows the correct value > * it assumes you can build road on the tile you are standing on > * waypoints might not work (but I think they do) > * it doesn't take into account that engineers build twice as fast as > workers. Here is an update of this patch. I didn't change anything just updated the server and common parts. So it's a bit shorter now. jason Index: ai/aiunit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v retrieving revision 1.334 diff -u -r1.334 aiunit.c --- ai/aiunit.c 1 Sep 2004 11:47:25 -0000 1.334 +++ ai/aiunit.c 3 Sep 2004 04:59:42 -0000 @@ -196,7 +196,7 @@ result = test_unit_move_to_tile(punit->type, unit_owner(punit), - ACTIVITY_IDLE, FALSE, punit->x, punit->y, + ACTIVITY_IDLE, punit->x, punit->y, dest_x, dest_y, unit_flag(punit, F_IGZOC)); if (result == MR_OK) { return 1; Index: client/control.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/control.c,v retrieving revision 1.139 diff -u -r1.139 control.c --- client/control.c 2 Aug 2004 16:59:14 -0000 1.139 +++ client/control.c 3 Sep 2004 04:59:42 -0000 @@ -633,6 +633,12 @@ /* Enter or change the hover connect state. */ set_hover_state(punit_focus, HOVER_CONNECT, activity); update_unit_info_label(punit_focus); + + enter_goto_state(punit_focus); + create_line_at_mouse_pos(); + } else { + assert(goto_is_active()); + goto_add_waypoint(); } } @@ -1632,13 +1638,23 @@ void do_unit_connect(struct unit *punit, int x, int y, enum unit_activity activity) { - struct packet_unit_connect req; + if (is_air_unit(punit)) { + append_output_window(_("Game: Sorry, airunit connect " + "not yet implemented.")); + } else { + int dest_x, dest_y; - req.activity_type = activity; - req.unit_id = punit->id; - req.dest_x = x; - req.dest_y = y; - send_packet_unit_connect(&aconnection, &req); + draw_line(x, y); + get_line_dest(&dest_x, &dest_y); + if (same_pos(dest_x, dest_y, x, y)) { + send_connect_route(punit, activity); + } else { + append_output_window(_("Game: Didn't find a route to " + "the destination!")); + } + } + + set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST); } /************************************************************************** Index: client/goto.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/goto.c,v retrieving revision 1.71 diff -u -r1.71 goto.c --- client/goto.c 26 Aug 2004 18:37:51 -0000 1.71 +++ client/goto.c 3 Sep 2004 04:59:43 -0000 @@ -75,11 +75,15 @@ static void decrement_drawn(int src_x, int src_y, enum direction8 dir); static void reset_last_part(void); +static int get_activity_time(int map_x, int map_y, struct player *pplayer); + + /************************************************************************** Various stuff for the goto routes **************************************************************************/ static bool is_active = FALSE; static bool is_init = FALSE; +static int connect_extra; /********************************************************************** Called once per game. @@ -196,7 +200,18 @@ p->end_x = x; p->end_y = y; p->end_moves_left = pf_last_position(p->path)->moves_left; - p->time = pf_last_position(p->path)->turn; + + if (hover_state == HOVER_CONNECT) { + int move_rate = goto_map.template.move_rate; + int moves = pf_last_position(p->path)->total_MC; + + p->time = moves / move_rate; + if (connect_extra > 0) { + p->time += connect_extra; + } + } else { + p->time = pf_last_position(p->path)->turn; + } /* Refresh tiles so turn information is shown. */ refresh_tile_mapcanvas(old_x, old_y, FALSE); @@ -246,6 +261,7 @@ p->start_x = prev->end_x; p->start_y = prev->end_y; p->start_moves_left = prev->end_moves_left; + parameter.moves_left_initially = p->start_moves_left; } p->path = NULL; p->end_x = p->start_x; @@ -253,7 +269,6 @@ p->time = 0; parameter.start_x = p->start_x; parameter.start_y = p->start_y; - parameter.moves_left_initially = p->start_moves_left; p->map = pf_create_map(¶meter); } @@ -375,6 +390,202 @@ return TB_NORMAL; } +/**************************************************************************** + Return the number of MP needed to do the connect activity at this + position. A negative number means it's impossible. +****************************************************************************/ +static int get_activity_time(int map_x, int map_y, struct player *pplayer) +{ + struct tile *ptile = map_get_tile(map_x, map_y); + struct tile_type *ttype = get_tile_type(ptile->terrain); + int activity_mc = 0; + + assert(hover_state == HOVER_CONNECT); + + switch (connect_activity) { + case ACTIVITY_IRRIGATE: + if (ttype->irrigation_time == 0) { + return -1; + } + if (map_has_special(map_x, map_y, S_MINE)) { + /* Don't overwrite mines. */ + return -1; + } + + if (tile_has_special(ptile, S_IRRIGATION)) { + break; + } + + activity_mc = ttype->irrigation_time; + break; + case ACTIVITY_ROAD: + assert(terrain_control.may_road); + if (tile_has_special(ptile, S_ROAD)) { + break; + } + if (ttype->road_time == 0 + || (tile_has_special(ptile, S_RIVER) + && !player_knows_techs_with_flag(pplayer, TF_BRIDGE))) { + /* 0 means road is impossible here (??) */ + return -1; + } + activity_mc = ttype->road_time; + break; + case ACTIVITY_RAILROAD: + assert(terrain_control.may_road); + if (!map_has_special(map_x, map_y, S_RAILROAD) + && (ttype->road_time == 0 + || (map_has_special(map_x, map_y, S_RIVER) + && !player_knows_techs_with_flag(pplayer, + TF_BRIDGE)))) { + return -1; + } + + if (tile_has_special(ptile, S_RAILROAD)) { + break; + } else { + if (!tile_has_special(ptile, S_ROAD)) { + /* Have to build road first. */ + activity_mc += ttype->road_time; + } + activity_mc += ttype->road_time; + } + break; + default: + die("Invalid connect activity."); + } + + return activity_mc; +} + +#if 0 +/**************************************************************************** + PF callback for the cost of a connect. In connect mode we are primarily + concerned with number of steps. +****************************************************************************/ +static int get_connect_MC(int src_x, int src_y, enum direction8 dir, + int dest_x, int dest_y, struct pf_parameter *param) +{ + int (*original_MC) (int src_x, int src_y, enum direction8 dir, + int dest_x, int dest_y, + struct pf_parameter *param) = param->data; + int base_mc = original_MC(src_x, src_y, dir, dest_x, dest_y, param); + int activity_mc = get_activity_MC(dest_x, dest_y, param); + int activity_mc2 = 0; + + if (same_pos(src_x, src_y, param->start_x, param->start_y)) { + activity_mc2 = get_activity_MC(src_x, src_y, param); + } + + if (base_mc == PF_IMPOSSIBLE_MC || activity_mc < 0 || activity_mc2 < 0) { + return PF_IMPOSSIBLE_MC; + } + + assert(hover_state == HOVER_CONNECT); + switch (connect_activity) { + case ACTIVITY_IRRIGATE: + if (!is_cardinal_dir(dir)) { + /* Only cardinal moves allowed. */ + return PF_IMPOSSIBLE_MC; + } + + /* Otherwise distance doesn't matter. */ + return 0; + case ACTIVITY_ROAD: + /* We just want a minimal distance path. */ + return SINGLE_MOVE; + case ACTIVITY_RAILROAD: + /* We don't care about distance, just build time. */ + return 0; + default: + break; + } + + assert(0); + return 0; +} +#endif + +/**************************************************************************** + PF jumbo callback for the cost of a connect by road. + In road-connect mode we are concerned with + (1) the number of steps of the resulting path + (2) (the tie-breaker) time to build the path (travel plus activity time). +****************************************************************************/ +static int get_connect_road(int src_x, int src_y, enum direction8 dir, + int dest_x, int dest_y, + int src_cost, int src_extra, + int *dest_cost, int *dest_extra, + struct pf_parameter *param) +{ + int activity_time; + int move_cost; + int moves_left; + int total_cost, total_extra; + + if (map_get_known(dest_x, dest_y, param->owner) == TILE_UNKNOWN) { + return -1; + } + + activity_time = get_activity_time(dest_x, dest_y, param->owner); + if (activity_time < 0) { + return -1; + } + + move_cost = param->get_MC(src_x, src_y, dir, dest_x, dest_y, param); + if (move_cost == PF_IMPOSSIBLE_MC) { + return -1; + } + + /* TODO: ZoC */ + + /* Ok, the move is possible. Does it give us good results? */ + + /* When connecting by road, we care most about the final distance */ + total_extra = src_extra + 1; + /* *dest_cost==-1 means we haven't reached dest until now */ + if (*dest_cost != -1 && total_extra > *dest_extra) { + /* No, this path is worse than what we already have */ + return -1; + } + + /* A special case: get_MC function doesn't know that we would have built + * a road on src tile by that time */ + if (map_has_special(dest_x, dest_y, S_ROAD)) { + move_cost = MOVE_COST_ROAD; + } + + move_cost = MIN(move_cost, param->move_rate); + total_cost = src_cost; + moves_left = param->move_rate - (src_cost % param->move_rate); + if (moves_left < move_cost) { + /* Emulating TM_WORST_TIME */ + total_cost += moves_left; + } + total_cost += move_cost; + + /* Now need to include the activity cost. If we have moves left, they + * will count as a full turn towards the activity time */ + moves_left = param->move_rate - (total_cost % param->move_rate); + if (activity_time > 0) { + activity_time--; + total_cost += moves_left; + } + total_cost += activity_time * param->move_rate; + + if (*dest_cost != -1 && total_extra == *dest_extra + && total_cost >= *dest_cost) { + /* New path has same length but longer construction time */ + return -1; + } + + /* Ok, we found a better path! */ + *dest_cost = total_cost; + *dest_extra = total_extra; + + return total_extra * PF_TURN_FACTOR + total_cost; +} + /********************************************************************** Fill the PF parameter with the correct client-goto values. ***********************************************************************/ @@ -385,6 +596,24 @@ assert(parameter->get_EC == NULL); parameter->get_EC = get_EC; assert(parameter->get_TB == NULL); + assert(parameter->get_MC != NULL); + if (hover_state == HOVER_CONNECT) { + connect_extra = get_activity_time(punit->x, punit->y, + unit_owner(punit)); + + /* FIXME: Do other activities */ + parameter->get_costs = get_connect_road; + parameter->is_pos_dangerous = NULL; + + assert(connect_extra >= 0); + if (connect_extra > 0) { + parameter->moves_left_initially = 0; + if (punit->moves_left == 0) { + connect_extra++; + } + } /* otherwise moves_left_initially = punit->moves_left (default) */ + } + if (is_attack_unit(punit) || is_diplomat_unit(punit)) { parameter->get_TB = get_TB_aggr; } else if (unit_flag(punit, F_TRADE_ROUTE) @@ -393,15 +622,16 @@ } else { parameter->get_TB = no_fights_or_unknown; } + + /* Note that in connect mode the "time" does not correspond to any actual + * move rate. */ parameter->turn_mode = TM_WORST_TIME; + parameter->start_x = punit->x; parameter->start_y = punit->y; /* Omniscience is always FALSE in the client */ parameter->omniscience = FALSE; - - /* May be overwritten by the caller. */ - parameter->moves_left_initially = punit->moves_left; } /********************************************************************** @@ -551,6 +781,7 @@ p.activity[i] = ACTIVITY_LAST; freelog(PACKET_LOG_LEVEL, " packet[%d] = move %s: %d,%d => %d,%d", i, dir_get_name(p.dir[i]), old_x, old_y, new_x, new_y); + p.activity[i] = ACTIVITY_LAST; } old_x = new_x; old_y = new_y; @@ -609,6 +840,87 @@ } /************************************************************************** + Send the current connect route (i.e., the one generated via HOVER_STATE) + to the server. +**************************************************************************/ +void send_connect_route(struct unit *punit, enum unit_activity activity) +{ + struct pf_path *path = NULL; + int i; + struct packet_unit_orders p; + int old_x, old_y; + + assert(is_active); + assert(punit->id == goto_map.unit_id); + + memset(&p, 0, sizeof(p)); + + for (i = 0; i < goto_map.num_parts; i++) { + path = pft_concat(path, goto_map.parts[i].path); + } + + p.unit_id = punit->id; + p.repeat = FALSE; + p.vigilant = FALSE; /* Should be TRUE? */ + + p.length = 0; + old_x = path->positions[0].x; + old_y = path->positions[0].y; + + for (i = 0; i < path->length; i++) { + switch (activity) { + case ACTIVITY_IRRIGATE: + if (!map_has_special(old_x, old_y, S_IRRIGATION)) { + /* Assume the unit can irrigate or we wouldn't be here. */ + p.orders[p.length] = ORDER_ACTIVITY; + p.activity[p.length] = ACTIVITY_IRRIGATE; + p.length++; + } + break; + case ACTIVITY_ROAD: + case ACTIVITY_RAILROAD: + if (!map_has_special(old_x, old_y, S_ROAD)) { + /* Assume the unit can build the road or we wouldn't be here. */ + p.orders[p.length] = ORDER_ACTIVITY; + p.activity[p.length] = ACTIVITY_ROAD; + p.length++; + } + if (activity == ACTIVITY_RAILROAD) { + if (!map_has_special(old_x, old_y, S_RAILROAD)) { + /* Assume the unit can build the rail or we wouldn't be here. */ + p.orders[p.length] = ORDER_ACTIVITY; + p.activity[p.length] = ACTIVITY_RAILROAD; + p.length++; + } + } + break; + default: + die("Invalid connect activity."); + break; + } + + if (i != path->length - 1) { + int new_x = path->positions[i + 1].x; + int new_y = path->positions[i + 1].y; + + assert(!same_pos(new_x, new_y, old_x, old_y)); + + p.orders[p.length] = ORDER_MOVE; + p.dir[p.length] = get_direction_for_step(old_x, old_y, new_x, new_y); + p.length++; + + old_x = new_x; + old_y = new_y; + } + } + + p.dest_x = old_x; + p.dest_y = old_y; + + send_packet_unit_orders(&aconnection, &p); +} + +/************************************************************************** Send the current goto route (i.e., the one generated via HOVER_STATE) to the server. The route might involve more than one part if waypoints were used. FIXME: danger paths are not supported. Index: client/goto.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/goto.h,v retrieving revision 1.13 diff -u -r1.13 goto.h --- client/goto.h 21 Jun 2004 15:14:43 -0000 1.13 +++ client/goto.h 3 Sep 2004 04:59:43 -0000 @@ -36,6 +36,7 @@ void send_goto_path(struct unit *punit, struct pf_path *path); void send_patrol_route(struct unit *punit); void send_goto_route(struct unit *punit); +void send_connect_route(struct unit *punit, enum unit_activity activity); struct pf_path *path_to_nearest_allied_city(struct unit *punit); Index: client/mapctrl_common.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v retrieving revision 1.39 diff -u -r1.39 mapctrl_common.c --- client/mapctrl_common.c 2 Aug 2004 16:59:14 -0000 1.39 +++ client/mapctrl_common.c 3 Sep 2004 04:59:43 -0000 @@ -625,7 +625,9 @@ **************************************************************************/ void update_line(int canvas_x, int canvas_y) { - if ((hover_state == HOVER_GOTO || hover_state == HOVER_PATROL) + if ((hover_state == HOVER_GOTO + || hover_state == HOVER_PATROL + || hover_state == HOVER_CONNECT) && draw_goto_line) { int x, y, old_x, old_y; @@ -645,7 +647,9 @@ ****************************************************************************/ void overview_update_line(int overview_x, int overview_y) { - if ((hover_state == HOVER_GOTO || hover_state == HOVER_PATROL) + if ((hover_state == HOVER_GOTO + || hover_state == HOVER_PATROL + || hover_state == HOVER_CONNECT) && draw_goto_line) { int x, y, old_x, old_y; Index: client/packhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v retrieving revision 1.400 diff -u -r1.400 packhand.c --- client/packhand.c 31 Aug 2004 04:40:48 -0000 1.400 +++ client/packhand.c 3 Sep 2004 04:59:43 -0000 @@ -105,7 +105,6 @@ } punit->activity_target = packet->activity_target; punit->paradropped = packet->paradropped; - punit->connecting = packet->connecting; punit->done_moving = packet->done_moving; punit->occupy = packet->occupy; if (packet->transported) { @@ -1184,7 +1183,6 @@ clear_goto_dest(punit); } punit->paradropped = packet_unit->paradropped; - punit->connecting = packet_unit->connecting; if (punit->done_moving != packet_unit->done_moving) { punit->done_moving = packet_unit->done_moving; check_focus = TRUE; Index: client/tilespec.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v retrieving revision 1.196 diff -u -r1.196 tilespec.c --- client/tilespec.c 25 Aug 2004 18:24:18 -0000 1.196 +++ client/tilespec.c 3 Sep 2004 04:59:44 -0000 @@ -2002,13 +2002,11 @@ } } - if (punit->connecting) { - ADD_SPRITE_FULL(sprites.unit.connect); - } - if (unit_has_orders(punit)) { if (punit->orders.repeat) { ADD_SPRITE_FULL(sprites.unit.patrol); + } else if (punit->activity != ACTIVITY_IDLE) { + ADD_SPRITE_SIMPLE(sprites.unit.connect); } else { ADD_SPRITE_FULL(sprites.unit.go_to); } Index: common/packets.def =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v retrieving revision 1.45 diff -u -r1.45 packets.def --- common/packets.def 3 Sep 2004 03:56:58 -0000 1.45 +++ common/packets.def 3 Sep 2004 04:59:44 -0000 @@ -727,13 +727,6 @@ CITY city_id; end -PACKET_UNIT_CONNECT=66;cs - UNIT unit_id; - ACTIVITY activity_type; - COORD dest_x; - COORD dest_y; -end - PACKET_UNIT_BRIBE_INQ=67;cs,handle-per-conn,dsend UNIT unit_id; end Index: common/unit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v retrieving revision 1.216 diff -u -r1.216 unit.c --- common/unit.c 31 Aug 2004 04:40:50 -0000 1.216 +++ common/unit.c 3 Sep 2004 04:59:45 -0000 @@ -785,9 +785,6 @@ (current == ACTIVITY_FORTIFIED) ? ACTIVITY_FORTIFYING : current; bool result; - if (punit->connecting) - return can_unit_do_connect(punit, current); - punit->activity = ACTIVITY_IDLE; punit->activity_target = S_NO_SPECIAL; @@ -1012,7 +1009,6 @@ punit->activity=new_activity; punit->activity_count=0; punit->activity_target = S_NO_SPECIAL; - punit->connecting = FALSE; if (new_activity == ACTIVITY_IDLE && punit->moves_left > 0) { /* No longer done. */ punit->done_moving = FALSE; @@ -1502,14 +1498,14 @@ bool igzoc) { return MR_OK == test_unit_move_to_tile(punit->type, unit_owner(punit), - punit->activity, punit->connecting, + punit->activity, punit->x, punit->y, dest_x, dest_y, igzoc); } /************************************************************************** unit can be moved if: - 1) the unit is idle or on goto or connecting. + 1) the unit is idle or on server goto. 2) the target location is on the map 3) the target location is next to the unit 4) there are no non-allied units on the target tile @@ -1524,9 +1520,9 @@ enum unit_move_result test_unit_move_to_tile(Unit_Type_id type, struct player *unit_owner, enum unit_activity activity, - bool connecting, int src_x, - int src_y, int dest_x, - int dest_y, bool igzoc) + int src_x, int src_y, + int dest_x, int dest_y, + bool igzoc) { struct tile *pfromtile, *ptotile; bool zoc; @@ -1534,8 +1530,7 @@ /* 1) */ if (activity != ACTIVITY_IDLE - && activity != ACTIVITY_GOTO - && !connecting) { + && activity != ACTIVITY_GOTO) { return MR_BAD_ACTIVITY; } @@ -1744,7 +1739,6 @@ punit->moves_left = unit_move_rate(punit); punit->moved = FALSE; punit->paradropped = FALSE; - punit->connecting = FALSE; punit->done_moving = FALSE; if (is_barbarian(pplayer)) { punit->fuel = BARBARIAN_LIFE; Index: common/unit.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v retrieving revision 1.123 diff -u -r1.123 unit.h --- common/unit.h 3 Sep 2004 04:22:37 -0000 1.123 +++ common/unit.h 3 Sep 2004 04:59:45 -0000 @@ -160,7 +160,6 @@ bool debug; bool moved; bool paradropped; - bool connecting; /* This value is set if the unit is done moving for this turn. This * information is used by the client. The invariant is: @@ -335,9 +334,9 @@ enum unit_move_result test_unit_move_to_tile(Unit_Type_id type, struct player *unit_owner, enum unit_activity activity, - bool connecting, int src_x, - int src_y, int dest_x, - int dest_y, bool igzoc); + int src_x, int src_y, + int dest_x, int dest_y, + bool igzoc); bool unit_type_really_ignores_zoc(Unit_Type_id type); bool zoc_ok_move(struct unit *punit, int x, int y); Index: common/aicore/path_finding.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/aicore/path_finding.c,v retrieving revision 1.21 diff -u -r1.21 path_finding.c --- common/aicore/path_finding.c 6 Aug 2004 13:43:12 -0000 1.21 +++ common/aicore/path_finding.c 3 Sep 2004 04:59:45 -0000 @@ -106,7 +106,6 @@ struct pf_node *lattice; /* Lattice of nodes */ utiny_t *status; /* Array of node statuses * (enum pf_node_status really) */ - bool extras; /* Are any extra-cost callbacks supplied? */ struct pqueue *danger_queue; /* Dangerous positions go there */ struct danger_node *d_lattice; /* Lattice with danger stuff */ }; @@ -189,7 +188,7 @@ Calculates cached values of the target node: node_known_type and zoc ******************************************************************/ -static void init_node(struct pf_map *pf_map, struct pf_node * node, +static void init_node(struct pf_map *pf_map, struct pf_node *node, int x, int y) { struct pf_parameter *params = pf_map->params; @@ -232,7 +231,6 @@ } } - /***************************************************************** Obtain cost-of-path from pure cost and extra cost *****************************************************************/ @@ -241,6 +239,72 @@ return PF_TURN_FACTOR * cost + extra * pf_map->params->move_rate; } +/************************************************************************** + Bare-bones PF iterator. All Freeciv rules logic is hidden in get_costs + callback (compare to pf_next function). + Plan: 1. Process previous position + 2. Get new nearest position and return it +**************************************************************************/ +static bool jumbo_iterate_map(struct pf_map *pf_map) +{ + mapindex_t index; + struct pf_node *node = &pf_map->lattice[pf_map->index]; + + pf_map->status[pf_map->index] = NS_PROCESSED; + + /* Processing Stage */ + /* The previous position is contained in {x,y} fields of map */ + + adjc_dir_iterate(pf_map->x, pf_map->y, x1, y1, dir) { + mapindex_t index1 = map_pos_to_index(x1, y1); + struct pf_node *node1 = &pf_map->lattice[index1]; + utiny_t *status = &pf_map->status[index1]; + int priority; + + + if (*status == NS_PROCESSED) { + /* This gives 15% speedup */ + continue; + } + + if (*status == NS_UNINIT) { + node1->cost = -1; + } + + /* User-supplied callback get_costs takes care of everything (ZOC, + * known, costs etc). See explanations in path_finding.h */ + priority = pf_map->params->get_costs(pf_map->x, pf_map->y, dir, x1, y1, + node->cost, node->extra_cost, + &node1->cost, &node1->extra_cost, + pf_map->params); + if (priority >= 0) { + /* We found a better route to xy1, record it + * (the costs are recorded already) */ + *status = NS_NEW; + node1->dir_to_here = dir; + pq_insert(pf_map->queue, index1, -priority); + } + + } adjc_dir_iterate_end; + + /* Get the next nearest node */ + for (;;) { + bool removed = pq_remove(pf_map->queue, &index); + + if (!removed) { + return FALSE; + } + if (pf_map->status[index] == NS_NEW) { + break; + } + /* If the node has already been processed, get the next one. */ + } + + pf_map->index = index; + index_to_map_pos(&(pf_map->x), &(pf_map->y), index); + + return TRUE; +} /***************************************************************** Primary method for iterative path-finding. @@ -257,6 +321,11 @@ return danger_iterate_map(pf_map); } + if (pf_map->params->get_costs) { + /* It is somewhat different when we have the jumbo callback */ + return jumbo_iterate_map(pf_map); + } + pf_map->status[pf_map->index] = NS_PROCESSED; /* There is no exit from DONT_LEAVE tiles! */ @@ -308,17 +377,10 @@ cost += node->cost; /* Evaluate the extra cost if it's relevant */ - if (pf_map->extras) { + if (pf_map->params->get_EC) { extra = node->extra_cost; - if (pf_map->params->get_EC) { - /* Add the cached value */ - extra += node1->extra_tile; - } - if (pf_map->params->get_moveEC) { - /* This one cannot be cached */ - extra += pf_map->params->get_moveEC(pf_map->x, pf_map->y, dir, - x1, y1, pf_map->params); - } + /* Add the cached value */ + extra += node1->extra_tile; } /* Update costs and add to queue, if we found a better route to xy1. */ @@ -336,8 +398,7 @@ } } - } - adjc_dir_iterate_end; + } adjc_dir_iterate_end; } /* Get the next nearest node */ @@ -417,13 +478,9 @@ pf_map->d_lattice[pf_map->index].step = 0; } - pf_map->extras = (parameter->get_EC != NULL - || parameter->get_moveEC != NULL); - return pf_map; } - /********************************************************************* After usage the map must be destroyed. *********************************************************************/ Index: common/aicore/path_finding.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/aicore/path_finding.h,v retrieving revision 1.8 diff -u -r1.8 path_finding.h --- common/aicore/path_finding.h 6 Aug 2004 13:43:12 -0000 1.8 +++ common/aicore/path_finding.h 3 Sep 2004 04:59:45 -0000 @@ -324,11 +324,6 @@ int (*get_EC) (int x, int y, enum known_type known, struct pf_parameter * param); - /* Same as above but this extra cost may depend on both origin and target - * tiles. Can be NULL. */ - int (*get_moveEC) (int from_x, int from_y, enum direction8 dir, - int to_x, int to_y, struct pf_parameter * param); - /* Although the rules governing ZoC are universal, the amount of * information available at server and client is different. To * compensate for it, we might need to supply our own version @@ -344,6 +339,32 @@ bool (*is_pos_dangerous) (int x, int y, enum known_type, struct pf_parameter * param); + /* This is a jumbo callback which overrides all previous ones. It takes + * care of everything (ZOC, known, costs etc). + * Variables: + * from_x, from_y -- position of the source tile + * from_cost, from_extra -- costs of the source tile + * to_x, to_y -- position of the dest tile + * to_cost, to_extra -- costs of the dest tile + * dir -- direction from source to dest + * param -- a pointer to this struct + * If the dest tile hasn't been reached before, to_cost is -1. + * + * The callback should: + * - evaluate the costs of the move + * - calculate the cost of the whole path + * - compare it to the ones recorded at dest tile + * - if new cost are not better, return -1 + * - if new costs are better, record them in to_cost/to_extra and return + * the cost-of-the-path which is the overall measure of goodness of the + * path (less is better) and used to order newly discovered locations. */ + int (*get_costs) (int from_x, int from_y, + enum direction8 dir, + int to_x, int to_y, + int from_cost, int from_extra, + int *to_cost, int *to_extra, + struct pf_parameter *param); + /* User provided data. Can be used to attach arbitrary information * to the map. */ void *data; Index: common/aicore/pf_tools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/aicore/pf_tools.c,v retrieving revision 1.20 diff -u -r1.20 pf_tools.c --- common/aicore/pf_tools.c 25 Aug 2004 18:24:20 -0000 1.20 +++ common/aicore/pf_tools.c 3 Sep 2004 04:59:45 -0000 @@ -544,7 +544,6 @@ parameter->turn_mode = TM_CAPPED; parameter->get_TB = NULL; parameter->get_EC = NULL; - parameter->get_moveEC = NULL; parameter->is_pos_dangerous = NULL; parameter->get_zoc = NULL; BV_CLR_ALL(parameter->unit_flags); Index: server/gotohand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v retrieving revision 1.183 diff -u -r1.183 gotohand.c --- server/gotohand.c 1 Sep 2004 19:54:18 -0000 1.183 +++ server/gotohand.c 3 Sep 2004 04:59:46 -0000 @@ -1314,7 +1314,6 @@ if (same_pos(punit->x, punit->y, dest_x, dest_y) || !goto_is_sane(punit, dest_x, dest_y, FALSE)) { punit->activity = ACTIVITY_IDLE; - punit->connecting = FALSE; send_unit_info(NULL, punit); if (same_pos(punit->x, punit->y, dest_x, dest_y)) { return GR_ARRIVED; @@ -1342,7 +1341,6 @@ pplayer->name, unit_type(punit)->name, punit->x, punit->y, dest_x, dest_y); punit->activity = ACTIVITY_IDLE; - punit->connecting = FALSE; send_unit_info(NULL, punit); return GR_FAILED; } @@ -1406,13 +1404,6 @@ return GR_OUT_OF_MOVEPOINTS; } - /* single step connecting unit when it can do it's activity */ - if (punit->connecting - && can_unit_do_activity(punit, punit->activity)) { - /* for connecting unit every step is a destination */ - return GR_ARRIVED; - } - freelog(LOG_DEBUG, "Moving on."); } while(!same_pos(x, y, waypoint_x, waypoint_y)); } else { @@ -1421,17 +1412,11 @@ pplayer->name, unit_type(punit)->name, punit->x, punit->y, dest_x, dest_y); handle_unit_activity_request(punit, ACTIVITY_IDLE); - punit->connecting = FALSE; send_unit_info(NULL, punit); return GR_FAILED; } /** Finished moving the unit for this turn **/ - /* ensure that the connecting unit will perform it's activity - on the destination file too. */ - if (punit->connecting && can_unit_do_activity(punit, punit->activity)) - return GR_ARRIVED; - /* normally we would just do this unconditionally, but if we had an airplane goto we might not be finished even if the loop exited */ if (same_pos(punit->x, punit->y, dest_x, dest_y)) { @@ -1442,7 +1427,6 @@ status = GR_OUT_OF_MOVEPOINTS; } - punit->connecting = FALSE; send_unit_info(NULL, punit); return status; } Index: server/savegame.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v retrieving revision 1.183 diff -u -r1.183 savegame.c --- server/savegame.c 3 Sep 2004 01:21:03 -0000 1.183 +++ server/savegame.c 3 Sep 2004 04:59:47 -0000 @@ -1289,9 +1289,6 @@ = secfile_lookup_int_default(file, (int) S_NO_SPECIAL, "player%d.u%d.activity_target", plrno, i); - punit->connecting - = secfile_lookup_bool_default(file, FALSE, - "player%d.u%d.connecting", plrno, i); punit->done_moving = secfile_lookup_bool_default(file, (punit->moves_left == 0), "player%d.u%d.done_moving", plrno, i); @@ -1360,7 +1357,7 @@ "player%d.u%d.activity_list", plrno, i); punit->has_orders = TRUE; for (j = 0; j < len; j++) { - if (orders_buf[j] == '\0' || dir_buf == '\0' + if (orders_buf[j] == '\0' || dir_buf[j] == '\0' || act_buf[j] == '\0') { freelog(LOG_ERROR, _("Savegame error: invalid unit orders.")); free_unit_orders(punit); @@ -2405,9 +2402,6 @@ secfile_insert_int(file, punit->activity_target, "player%d.u%d.activity_target", plrno, i); - secfile_insert_bool(file, punit->connecting, - "player%d.u%d.connecting", - plrno, i); secfile_insert_bool(file, punit->done_moving, "player%d.u%d.done_moving", plrno, i); secfile_insert_int(file, punit->moves_left, "player%d.u%d.moves", Index: server/unithand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v retrieving revision 1.303 diff -u -r1.303 unithand.c --- server/unithand.c 26 Aug 2004 18:37:52 -0000 1.303 +++ server/unithand.c 3 Sep 2004 04:59:47 -0000 @@ -101,44 +101,6 @@ } /************************************************************************** -Handler for PACKET_UNIT_CONNECT request. The unit is send on way and will -build something (roads only for now) along the way, using server-side -path-finding. - -FIXME: This should be rewritten to use client-side path finding along so -that we can show in the client where the road-to-be-built will be and -enable the use of waypoints to alter this route. - Per -**************************************************************************/ -void handle_unit_connect(struct player *pplayer, int unit_id, - enum unit_activity activity_type, int dest_x, - int dest_y) -{ - struct unit *punit = player_find_unit_by_id(pplayer, unit_id); - - if (!is_normal_map_pos(dest_x, dest_y) || !punit - || !can_unit_do_connect(punit, activity_type)) { - return; - } - - set_goto_dest(punit, dest_x, dest_y); - - set_unit_activity(punit, activity_type); - punit->connecting = TRUE; - - send_unit_info(NULL, punit); - - /* - * Avoid wasting first turn if unit cannot do the activity on the - * starting tile. - */ - if (!can_unit_do_activity(punit, activity_type)) { - (void) do_unit_goto(punit, - get_activity_move_restriction(activity_type), - FALSE); - } -} - -/************************************************************************** Upgrade all units of a given type. **************************************************************************/ void handle_unit_type_upgrade(struct player *pplayer, Unit_Type_id type) @@ -947,7 +909,7 @@ reason = test_unit_move_to_tile(punit->type, unit_owner(punit), - punit->activity, punit->connecting, + punit->activity, punit->x, punit->y, dest_x, dest_y, igzoc); if (reason == MR_OK) return TRUE; @@ -1625,6 +1587,7 @@ return; } + for (i = 0; i < packet->length; i++) { switch (packet->orders[i]) { case ORDER_MOVE: Index: server/unittools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v retrieving revision 1.301 diff -u -r1.301 unittools.c --- server/unittools.c 3 Sep 2004 03:56:59 -0000 1.301 +++ server/unittools.c 3 Sep 2004 04:59:48 -0000 @@ -593,20 +593,6 @@ unit_restore_movepoints(pplayer, punit); - if (punit->connecting && !can_unit_do_activity(punit, activity)) { - punit->activity_count = 0; - if (do_unit_goto(punit, get_activity_move_restriction(activity), FALSE) - == GR_DIED) { - return; - } - } - - /* if connecting, automagically build prerequisities first */ - if (punit->connecting && activity == ACTIVITY_RAILROAD && - !map_has_special(punit->x, punit->y, S_ROAD)) { - activity = ACTIVITY_ROAD; - } - if (activity == ACTIVITY_EXPLORE) { bool more_to_explore = ai_manage_explorer(punit); @@ -779,18 +765,8 @@ send_tile_info(NULL, punit->x, punit->y); unit_list_iterate (map_get_tile(punit->x, punit->y)->units, punit2) { if (punit2->activity == activity) { - bool alive = TRUE; - if (punit2->connecting) { - punit2->activity_count = 0; - alive = (do_unit_goto(punit2, - get_activity_move_restriction(activity), - FALSE) != GR_DIED); - } else { - set_unit_activity(punit2, ACTIVITY_IDLE); - } - if (alive) { - send_unit_info(NULL, punit2); - } + set_unit_activity(punit2, ACTIVITY_IDLE); + send_unit_info(NULL, punit2); } } unit_list_iterate_end; } @@ -1831,7 +1807,6 @@ } packet->activity_target = punit->activity_target; packet->paradropped = punit->paradropped; - packet->connecting = punit->connecting; packet->done_moving = punit->done_moving; if (punit->transported_by == -1) { packet->transported = FALSE; @@ -2625,8 +2600,7 @@ if (punit->activity != ACTIVITY_IDLE && punit->activity != ACTIVITY_SENTRY && punit->activity != ACTIVITY_EXPLORE - && punit->activity != ACTIVITY_GOTO - && !punit->connecting) { + && punit->activity != ACTIVITY_GOTO) { set_unit_activity(punit, ACTIVITY_IDLE); } }
|