<URL: http://bugs.freeciv.org/Ticket/Display.html?id=39817 >
Apparently, I forgot to attach the patch.... Here's S2_2 at the current revision:
Index: client/control.c =================================================================== --- client/control.c (revision 13927) +++ client/control.c (working copy) @@ -50,14 +50,17 @@ /* gui-dep code may adjust depending on tile size etc: */ int num_units_below = MAX_NUM_UNITS_BELOW; -/* unit_focus points to the current unit in focus */ -static struct unit_list *pfocus_units; +/* current_focus points to the current unit(s) in focus */ +static struct unit_list *current_focus; -/* The previously focused unit. Focus can generally be recalled on this - * unit with keypad 5. FIXME: this is not reset when the client - * disconnects. */ +/* The previously focused unit(s). Focus can generally be recalled + * with keypad 5 (or the equivalent). + * FIXME: this is not reset when the client disconnects. */ static struct unit_list *previous_focus; +/* The priority focused unit(s). */ +static struct unit_list *priority_focus; + /* These should be set via set_hover_state() */ enum cursor_hover_state hover_state = HOVER_NONE; struct tile *hover_tile = NULL; @@ -83,9 +86,8 @@ /*************************************************************************/ static struct unit *find_best_focus_candidate(bool accept_current); -static void store_focus(void); static struct unit *quickselect(struct tile *ptile, - enum quickselect_type qtype); + enum quickselect_type qtype); /************************************************************************** Called only by main() in client/civclient.c. @@ -96,8 +98,11 @@ caravan_arrival_queue = genlist_new(); diplomat_arrival_queue = genlist_new(); - pfocus_units = unit_list_new(); + + current_focus = unit_list_new(); previous_focus = unit_list_new(); + priority_focus = unit_list_new(); + for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) { battlegroups[i] = unit_list_new(); } @@ -112,14 +117,55 @@ genlist_free(caravan_arrival_queue); genlist_free(diplomat_arrival_queue); - unit_list_free(pfocus_units); + + unit_list_free(current_focus); unit_list_free(previous_focus); + unit_list_free(priority_focus); + for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) { unit_list_free(battlegroups[i]); } } /************************************************************************** +... +**************************************************************************/ +struct unit_list *get_units_in_focus(void) +{ + return current_focus; +} + +/**************************************************************************** + Return the number of units currently in focus (0 or more). +****************************************************************************/ +int get_num_units_in_focus(void) +{ + return unit_list_size(current_focus); +} + +/************************************************************************** + Store the focus unit(s). This is used so that we can return to the + previously focused unit with an appropriate keypress. +**************************************************************************/ +static void store_previous_focus(void) +{ + if (get_num_units_in_focus() > 0) { + unit_list_unlink_all(previous_focus); + unit_list_iterate(get_units_in_focus(), punit) { + unit_list_append(previous_focus, punit); + } unit_list_iterate_end; + } +} + +/**************************************************************************** + Store a priority focus unit. +****************************************************************************/ +void urgent_unit_focus(struct unit *punit) +{ + unit_list_append(priority_focus, punit); +} + +/************************************************************************** Called when a unit is killed; this removes it from the control lists. **************************************************************************/ void control_unit_killed(struct unit *punit) @@ -127,12 +173,16 @@ int i; goto_unit_killed(punit); + unit_list_unlink(get_units_in_focus(), punit); if (get_num_units_in_focus() < 1) { set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST); } update_unit_info_label(get_units_in_focus()); + unit_list_unlink(previous_focus, punit); + unit_list_unlink(priority_focus, punit); + for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) { unit_list_unlink(battlegroups[i], punit); } @@ -216,7 +266,7 @@ ****************************************************************************/ struct unit *head_of_units_in_focus(void) { - return unit_list_get(pfocus_units, 0); + return unit_list_get(current_focus, 0); } /**************************************************************************** @@ -249,6 +299,28 @@ } /************************************************************************** + ... +**************************************************************************/ +static void current_focus_append(struct unit *punit) +{ + unit_list_append(current_focus, punit); + + punit->focus_status = FOCUS_AVAIL; + refresh_unit_mapcanvas(punit, punit->tile, TRUE, FALSE); + + if (unit_has_orders(punit)) { + /* Clear the focus unit's orders. */ + request_orders_cleared(punit); + } + + if (punit->activity != ACTIVITY_IDLE || punit->ai.control) { + punit->ai.control = FALSE; + refresh_unit_city_dialogs(punit); + request_new_unit_activity(punit, ACTIVITY_IDLE); + } +} + +/************************************************************************** Sets the focus unit directly. The unit given will be given the focus; if NULL the focus will be cleared. @@ -270,19 +342,16 @@ * solution would be a set_units_focus() */ if (!(get_num_units_in_focus() == 1 && punit == head_of_units_in_focus())) { - store_focus(); + store_previous_focus(); focus_changed = TRUE; } /* Redraw the old focus unit (to fix blinking or remove the selection * circle). */ - unit_list_iterate(pfocus_units, punit_old) { + unit_list_iterate(current_focus, punit_old) { refresh_unit_mapcanvas(punit_old, punit_old->tile, TRUE, FALSE); } unit_list_iterate_end; - unit_list_unlink_all(pfocus_units); - if (punit) { - unit_list_append(pfocus_units, punit); - } + unit_list_unlink_all(current_focus); if (!can_client_change_view()) { /* This function can be called to set the focus to NULL when @@ -291,28 +360,16 @@ return; } - if(punit) { + if (NULL != punit) { auto_center_on_focus_unit(); - - punit->focus_status=FOCUS_AVAIL; - refresh_unit_mapcanvas(punit, punit->tile, TRUE, FALSE); - - if (unit_has_orders(punit)) { - /* Clear the focus unit's orders. */ - request_orders_cleared(punit); - } - if (punit->activity != ACTIVITY_IDLE || punit->ai.control) { - punit->ai.control = FALSE; - refresh_unit_city_dialogs(punit); - request_new_unit_activity(punit, ACTIVITY_IDLE); - } + current_focus_append(punit); } if (focus_changed) { set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST); } - update_unit_info_label(pfocus_units); + update_unit_info_label(current_focus); update_menus(); } @@ -338,19 +395,8 @@ set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST); } - unit_list_append(pfocus_units, punit); - punit->focus_status = FOCUS_AVAIL; - refresh_unit_mapcanvas(punit, punit->tile, TRUE, FALSE); - if (unit_has_orders(punit)) { - /* Clear the focus unit's orders. */ - request_orders_cleared(punit); - } - if (punit->activity != ACTIVITY_IDLE || punit->ai.control) { - punit->ai.control = FALSE; - refresh_unit_city_dialogs(punit); - request_new_unit_activity(punit, ACTIVITY_IDLE); - } - update_unit_info_label(pfocus_units); + current_focus_append(punit); + update_unit_info_label(current_focus); update_menus(); } @@ -366,20 +412,6 @@ } /************************************************************************** - Store the focus unit. This is used so that we can return to the - previously focused unit with an appropriate keypress. -**************************************************************************/ -static void store_focus(void) -{ - if (get_num_units_in_focus() > 0) { - unit_list_unlink_all(previous_focus); - unit_list_iterate(get_units_in_focus(), punit) { - unit_list_append(previous_focus, punit); - } unit_list_iterate_end; - } -} - -/************************************************************************** If there is no unit currently in focus, or if the current unit in focus should not be in focus, then get a new focus unit. We let GOTO-ing units stay in focus, so that if they have moves left @@ -415,22 +447,6 @@ } /************************************************************************** -... -**************************************************************************/ -struct unit_list *get_units_in_focus(void) -{ - return pfocus_units; -} - -/**************************************************************************** - Return the number of units currently in focus (0 or more). -****************************************************************************/ -int get_num_units_in_focus(void) -{ - return unit_list_size(pfocus_units); -} - -/************************************************************************** This function may be called from packhand.c, via update_unit_focus(), as a result of packets indicating change in activity for a unit. Also called when user press the "Wait" command. @@ -439,10 +455,12 @@ **************************************************************************/ void advance_unit_focus(void) { + struct unit *candidate = NULL; const int num_units_in_old_focus = get_num_units_in_focus(); - struct unit *candidate = find_best_focus_candidate(FALSE); - if (!game.player_ptr || !can_client_change_view()) { + if (!game.player_ptr + || !is_player_phase(game.player_ptr, game.info.phase) + || !can_client_change_view()) { set_unit_focus(NULL); return; } @@ -460,19 +478,44 @@ } } unit_list_iterate_end; - if(!candidate) { - /* First try for "waiting" units. */ - unit_list_iterate(game.player_ptr->units, punit) { - if(punit->focus_status == FOCUS_WAIT) { - punit->focus_status = FOCUS_AVAIL; - } - } unit_list_iterate_end; + if (unit_list_size(priority_focus) > 0) { + /* Try top of the urgent list. */ + candidate = unit_list_get(priority_focus, 0); + + if (get_num_units_in_focus() > 0) { + /* Rarely, more than one unit on the same tile will be in the list. */ + unit_list_iterate(priority_focus, punit) { + if (head_of_units_in_focus()->tile == punit->tile) { + /* Use the first one found */ + candidate = punit; + break; + } + } unit_list_iterate_end; + } + unit_list_unlink(priority_focus, candidate); + + /* Autocenter on Wakeup, regardless of the local option + * "auto_center_on_unit". */ + if (!tile_visible_and_not_on_border_mapcanvas(candidate->tile)) { + center_tile_mapcanvas(candidate->tile); + } + } else { candidate = find_best_focus_candidate(FALSE); - } - /* Accept current focus unit as last resort. */ - if (!candidate) { - candidate = find_best_focus_candidate(TRUE); + if (!candidate) { + /* Try for "waiting" units. */ + unit_list_iterate(game.player_ptr->units, punit) { + if(punit->focus_status == FOCUS_WAIT) { + punit->focus_status = FOCUS_AVAIL; + } + } unit_list_iterate_end; + candidate = find_best_focus_candidate(FALSE); + + if (!candidate) { + /* Accept current focus unit as last resort. */ + candidate = find_best_focus_candidate(TRUE); + } + } } set_unit_focus(candidate); @@ -500,12 +543,6 @@ { struct tile *ptile = get_center_tile_mapcanvas(); - if (!game.player_ptr - || !is_player_phase(game.player_ptr, game.info.phase)) { - /* No focus unit wanted. */ - return NULL; - } - if (!get_focus_unit_on_tile(ptile)) { struct unit *pfirst = head_of_units_in_focus(); @@ -1147,6 +1184,23 @@ } /************************************************************************** + ... +**************************************************************************/ +void wakeup_sentried_units(struct tile *ptile) +{ + if (!can_client_issue_orders()) { + return; + } + unit_list_iterate(ptile->units, punit) { + if (punit->activity == ACTIVITY_SENTRY + && game.player_ptr == unit_owner(punit)) { + request_new_unit_activity(punit, ACTIVITY_IDLE); + } + } + unit_list_iterate_end; +} + +/************************************************************************** (RP:) un-sentry all my own sentried units on punit's tile **************************************************************************/ void request_unit_wakeup(struct unit *punit) @@ -1222,23 +1276,6 @@ } /************************************************************************** - ... -**************************************************************************/ -void wakeup_sentried_units(struct tile *ptile) -{ - if (!can_client_issue_orders()) { - return; - } - unit_list_iterate(ptile->units, punit) { - if (punit->activity == ACTIVITY_SENTRY - && game.player_ptr == unit_owner(punit)) { - request_new_unit_activity(punit, ACTIVITY_IDLE); - } - } - unit_list_iterate_end; -} - -/************************************************************************** Player pressed 'b' or otherwise instructed unit to build or add to city. If the unit can build a city, we popup the appropriate dialog. Otherwise, we just send a packet to the server. @@ -2018,7 +2055,7 @@ convenient, and can be tactically important in furious multiplayer games. **************************************************************************/ static struct unit *quickselect(struct tile *ptile, - enum quickselect_type qtype) + enum quickselect_type qtype) { int listsize = unit_list_size(ptile->units); struct unit *panytransporter = NULL, @@ -2247,7 +2284,7 @@ } /************************************************************************** - Recall the previous focus unit and focus on it. See store_focus(). + Recall the previous focus unit(s). See store_previous_focus(). **************************************************************************/ void key_recall_previous_focus_unit(void) { Index: client/control.h =================================================================== --- client/control.h (revision 13927) +++ client/control.h (working copy) @@ -119,19 +119,23 @@ bool unit_is_in_focus(const struct unit *punit); struct unit *get_focus_unit_on_tile(const struct tile *ptile); struct unit *head_of_units_in_focus(void); -void auto_center_on_focus_unit(void); -void advance_unit_focus(void); struct unit_list *get_units_in_focus(void); int get_num_units_in_focus(void); + void set_unit_focus(struct unit *punit); +void set_unit_focus_and_select(struct unit *punit); void add_unit_focus(struct unit *punit); -void set_unit_focus_and_select(struct unit *punit); +void urgent_unit_focus(struct unit *punit); + +void advance_unit_focus(void); +void auto_center_on_focus_unit(void); void update_unit_focus(void); +void update_unit_pix_label(struct unit_list *punitlist); + struct unit *find_visible_unit(struct tile *ptile); void set_units_in_combat(struct unit *pattacker, struct unit *pdefender); double blink_active_unit(void); double blink_turn_done_button(void); -void update_unit_pix_label(struct unit_list *punitlist); void process_caravan_arrival(struct unit *punit); void process_diplomat_arrival(struct unit *pdiplomat, int victim_id); Index: client/packhand.c =================================================================== --- client/packhand.c (revision 13927) +++ client/packhand.c (working copy) @@ -1109,17 +1109,10 @@ && unit_owner(punit) == game.player_ptr && punit->activity == ACTIVITY_SENTRY && packet_unit->activity == ACTIVITY_IDLE - && is_player_phase(game.player_ptr, game.info.phase) - /* only 1 wakeup focus per tile is useful */ - && !get_focus_unit_on_tile(packet_unit->tile)) { - set_unit_focus(punit); + && is_player_phase(game.player_ptr, game.info.phase)) { + /* many wakeup units per tile are handled */ + urgent_unit_focus(punit); check_focus = FALSE; /* and keep it */ - - /* Autocenter on Wakeup, regardless of the local option - * "auto_center_on_unit". */ - if (!tile_visible_and_not_on_border_mapcanvas(punit->tile)) { - center_tile_mapcanvas(punit->tile); - } } punit->activity = packet_unit->activity;
_______________________________________________ Freeciv-dev mailing list Freeciv-dev@gna.org https://mail.gna.org/listinfo/freeciv-dev