From 21676ac1d6a498e3f3eb5e15d712ebdb625f0891 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 26 Nov 2022 14:20:57 +0200 Subject: [PATCH 39/39] Client: Add confirmable actions framework Requested by Alexandro Ignatiev See osdn #46115 Signed-off-by: Marko Lindqvist --- client/control.c | 84 ++++++++++++++++++++++++++++++++--- client/control.h | 10 +++++ client/gui-gtk-3.22/dialogs.c | 11 +++++ client/gui-gtk-4.0/dialogs.c | 10 +++++ client/gui-qt/dialogs.cpp | 10 +++++ client/gui-qt/qtg_cxxside.cpp | 2 + client/gui-qt/qtg_cxxside.h | 3 ++ client/gui-sdl2/dialogs.c | 10 +++++ client/gui-stub/dialogs.c | 13 ++++++ client/gui_interface.c | 9 ++++ client/gui_interface.h | 5 +++ client/include/dialogs_g.h | 5 ++- common/actions.h | 4 +- 13 files changed, 167 insertions(+), 9 deletions(-) diff --git a/client/control.c b/client/control.c index 39395164b3..eb560eb872 100644 --- a/client/control.c +++ b/client/control.c @@ -1657,6 +1657,30 @@ void request_unit_select(struct unit_list *punits, continent_hash_destroy(cont_table); } +/**********************************************************************//** + Return whether user should confirm the action. Buffer gets filled + with explanation of the situation. +**************************************************************************/ +static bool action_requires_confirmation(action_id act, + char *buf, size_t bufsize) +{ + fc_assert(buf != NULL || bufsize == 0); + + if (bufsize > 0) { + buf[0] = '\0'; + } + + if (act == ACTION_JOIN_CITY) { + if (bufsize > 0) { + fc_snprintf(buf, bufsize, _("Joining a city uses the unit")); + } + + return TRUE; + } + + return FALSE; +} + /**********************************************************************//** Request an actor unit to do a specific action. - action : The action to be requested. @@ -1671,14 +1695,62 @@ void request_unit_select(struct unit_list *punits, void request_do_action(action_id action, int actor_id, int target_id, int sub_tgt, const char *name) { - struct unit *actor_unit = game_unit_by_number(actor_id); + char buf[400]; + + if (action_requires_confirmation(action, buf, sizeof(buf))) { + struct act_confirmation_data *data = fc_malloc(sizeof(struct act_confirmation_data)); + + data->act = action; + data->actor = actor_id; + data->target = target_id; + data->tgt_sub = sub_tgt; + + if (name != NULL) { + data->name = fc_strdup(name); + } else { + data->name = NULL; + } + + request_action_confirmation(buf, data); + } else { + struct unit *actor_unit = game_unit_by_number(actor_id); + + /* Giving an order takes back control. */ + request_unit_ssa_set(actor_unit, SSA_NONE); + + dsend_packet_unit_do_action(&client.conn, + actor_id, target_id, sub_tgt, name, + action); + } +} + +/**********************************************************************//** + GUI (likely user) either confirmed the action, or not. + Even if not, we have to free the data. +**************************************************************************/ +void action_confirmation(struct act_confirmation_data *data, bool confirm) +{ + if (confirm) { + struct unit *actor_unit = game_unit_by_number(data->actor); + + if (actor_unit != NULL) { + /* Giving an order takes back control. */ + request_unit_ssa_set(actor_unit, SSA_NONE); + + dsend_packet_unit_do_action(&client.conn, + data->actor, + data->target, + data->tgt_sub, + data->name, + data->act); + } + } - /* Giving an order takes back control. */ - request_unit_ssa_set(actor_unit, SSA_NONE); + if (data->name != NULL) { + free(data->name); + } - dsend_packet_unit_do_action(&client.conn, - actor_id, target_id, sub_tgt, name, - action); + free(data); } /**********************************************************************//** diff --git a/client/control.h b/client/control.h index 7fb5f3f236..e2a4a0bf94 100644 --- a/client/control.h +++ b/client/control.h @@ -131,6 +131,15 @@ void request_unit_wakeup(struct unit *punit); #define SPECENUM_COUNT SELLOC_COUNT #include "specenum_gen.h" +struct act_confirmation_data +{ + action_id act; + int actor; + int target; + int tgt_sub; + char *name; +}; + void request_unit_select(struct unit_list *punits, enum unit_select_type_mode seltype, enum unit_select_location_mode selloc); @@ -138,6 +147,7 @@ void request_unit_select(struct unit_list *punits, void request_do_action(action_id action, int actor_id, int target_id, int sub_tgt, const char *name); void request_action_details(action_id action, int actor_id, int target_id); +void action_confirmation(struct act_confirmation_data *data, bool confirm); void request_toggle_city_outlines(void); void request_toggle_city_output(void); void request_toggle_map_grid(void); diff --git a/client/gui-gtk-3.22/dialogs.c b/client/gui-gtk-3.22/dialogs.c index abbec98922..2238f33c09 100644 --- a/client/gui-gtk-3.22/dialogs.c +++ b/client/gui-gtk-3.22/dialogs.c @@ -1572,3 +1572,14 @@ void popup_combat_info(int attacker_unit_id, int defender_unit_id, bool make_att_veteran, bool make_def_veteran) { } + +/**********************************************************************//** + Common code wants confirmation for an action. +**************************************************************************/ +void request_action_confirmation(const char *expl, + struct act_confirmation_data *data) +{ + log_normal("Got to confirm, because %s", expl); + + action_confirmation(data, TRUE); +} diff --git a/client/gui-gtk-4.0/dialogs.c b/client/gui-gtk-4.0/dialogs.c index 41bb98e484..e9206e392e 100644 --- a/client/gui-gtk-4.0/dialogs.c +++ b/client/gui-gtk-4.0/dialogs.c @@ -1597,3 +1597,13 @@ void popup_combat_info(int attacker_unit_id, int defender_unit_id, bool make_att_veteran, bool make_def_veteran) { } + +/**********************************************************************//** + Common code wants confirmation for an action. +**************************************************************************/ +void request_action_confirmation(const char *expl, + struct act_confirmation_data *data) +{ + /* TODO: Implement. Currently just pass everything as confirmed */ + action_confirmation(data, TRUE); +} diff --git a/client/gui-qt/dialogs.cpp b/client/gui-qt/dialogs.cpp index 428b36d5d6..91e625be04 100644 --- a/client/gui-qt/dialogs.cpp +++ b/client/gui-qt/dialogs.cpp @@ -4908,3 +4908,13 @@ void qtg_popup_combat_info(int attacker_unit_id, int defender_unit_id, gui()->battlelog_wdg->show(); } } + +/***********************************************************************//** + Common code wants confirmation for an action. +***************************************************************************/ +void qtg_request_action_confirmation(const char *expl, + struct act_confirmation_data *data) +{ + // TODO: Implement. Currently just pass everything as confirmed. + action_confirmation(data, TRUE); +} diff --git a/client/gui-qt/qtg_cxxside.cpp b/client/gui-qt/qtg_cxxside.cpp index 2710ec8d14..9a6fb19ba0 100644 --- a/client/gui-qt/qtg_cxxside.cpp +++ b/client/gui-qt/qtg_cxxside.cpp @@ -120,4 +120,6 @@ void setup_gui_funcs() funcs->gui_recv_create_clause = qtg_recv_create_clause; funcs->gui_recv_remove_clause = qtg_recv_remove_clause; funcs->gui_recv_accept_treaty = qtg_recv_accept_treaty; + + funcs->request_action_confirmation = qtg_request_action_confirmation; } diff --git a/client/gui-qt/qtg_cxxside.h b/client/gui-qt/qtg_cxxside.h index c7c502799f..e230745676 100644 --- a/client/gui-qt/qtg_cxxside.h +++ b/client/gui-qt/qtg_cxxside.h @@ -153,4 +153,7 @@ void qtg_recv_create_clause(struct Treaty *ptreaty, struct player *they); void qtg_recv_remove_clause(struct Treaty *ptreaty, struct player *they); void qtg_recv_accept_treaty(struct Treaty *ptreaty, struct player *they); +void qtg_request_action_confirmation(const char *expl, + struct act_confirmation_data *data); + #endif // FC__QTG_CXXSIDE_H diff --git a/client/gui-sdl2/dialogs.c b/client/gui-sdl2/dialogs.c index cef11c4478..1947d08c7c 100644 --- a/client/gui-sdl2/dialogs.c +++ b/client/gui-sdl2/dialogs.c @@ -3647,3 +3647,13 @@ void popup_combat_info(int attacker_unit_id, int defender_unit_id, bool make_att_veteran, bool make_def_veteran) { } + +/**********************************************************************//** + Common code wants confirmation for an action. +**************************************************************************/ +void request_action_confirmation(const char *expl, + struct act_confirmation_data *data) +{ + /* TODO: Implement. Currently just pass everything as confirmed */ + action_confirmation(data, TRUE); +} diff --git a/client/gui-stub/dialogs.c b/client/gui-stub/dialogs.c index 8c226f0b8a..f1bfd18c0f 100644 --- a/client/gui-stub/dialogs.c +++ b/client/gui-stub/dialogs.c @@ -19,6 +19,9 @@ #include "game.h" #include "government.h" +/* client */ +#include "control.h" + /* gui main header */ #include "gui_stub.h" @@ -360,3 +363,13 @@ void gui_popup_combat_info(int attacker_unit_id, int defender_unit_id, bool make_att_veteran, bool make_def_veteran) { } + +/**********************************************************************//** + Common code wants confirmation for an action. +**************************************************************************/ +void gui_request_action_confirmation(const char *expl, + struct act_confirmation_data *data) +{ + /* Just confirm */ + action_confirmation(data, TRUE); +} diff --git a/client/gui_interface.c b/client/gui_interface.c index 5a979a7820..d434ff8956 100644 --- a/client/gui_interface.c +++ b/client/gui_interface.c @@ -692,3 +692,12 @@ void gui_recv_accept_treaty(struct Treaty *ptreaty, struct player *they) { funcs.gui_recv_accept_treaty(ptreaty, they); } + +/**********************************************************************//** + Call request_action_confirmation callback +**************************************************************************/ +void request_action_confirmation(const char *expl, + struct act_confirmation_data *data) +{ + funcs.request_action_confirmation(expl, data); +} diff --git a/client/gui_interface.h b/client/gui_interface.h index 2fad37bf45..16d7fff3ca 100644 --- a/client/gui_interface.h +++ b/client/gui_interface.h @@ -31,6 +31,8 @@ extern "C" { /* client */ #include "tilespec.h" +struct act_confirmation_data; + struct gui_funcs { void (*ui_init)(void); int (*ui_main)(int argc, char *argv[]); @@ -157,6 +159,9 @@ struct gui_funcs { void (*gui_recv_create_clause)(struct Treaty *ptreaty, struct player *they); void (*gui_recv_remove_clause)(struct Treaty *ptreaty, struct player *they); void (*gui_recv_accept_treaty)(struct Treaty *ptreaty, struct player *they); + + void (*request_action_confirmation)(const char *expl, + struct act_confirmation_data *data); }; struct gui_funcs *get_gui_funcs(void); diff --git a/client/include/dialogs_g.h b/client/include/dialogs_g.h index 9b120f8faa..dacb0409c7 100644 --- a/client/include/dialogs_g.h +++ b/client/include/dialogs_g.h @@ -28,6 +28,7 @@ #include "gui_proto_constructor.h" struct packet_nations_selected_info; +struct act_confirmation_data; GUI_FUNC_PROTO(void, popup_notify_goto_dialog, const char *headline, const char *lines, @@ -86,7 +87,9 @@ GUI_FUNC_PROTO(bool, handmade_scenario_warning, void) GUI_FUNC_PROTO(void, popdown_all_game_dialogs, void) GUI_FUNC_PROTO(bool, request_transport, struct unit *pcargo, struct tile *ptile) +GUI_FUNC_PROTO(void, request_action_confirmation, const char *expl, + struct act_confirmation_data *data) GUI_FUNC_PROTO(void, update_infra_dialog, void) -#endif /* FC__DIALOGS_G_H */ +#endif /* FC__DIALOGS_G_H */ diff --git a/common/actions.h b/common/actions.h index f8d4e60858..eb801f1706 100644 --- a/common/actions.h +++ b/common/actions.h @@ -956,10 +956,10 @@ bool action_immune_government(struct government *gov, action_id act); bool is_action_possible_on_city(action_id act_id, const struct player *actor_player, - const struct city* target_city); + const struct city *target_city); bool action_maybe_possible_actor_unit(const action_id wanted_action, - const struct unit* actor_unit); + const struct unit *actor_unit); bool action_mp_full_makes_legal(const struct unit *actor, const action_id act_id); -- 2.35.1