Feature #1686 » 0018-Drop-gtk4x-sources.patch
bootstrap/org.freeciv.gtk4x.desktop | ||
---|---|---|
[Desktop Entry]
|
||
Name=Freeciv
|
||
Name[ca]=Freeciv
|
||
Name[es]=Freeciv
|
||
Name[fr]=Freeciv
|
||
Name[nb]=Freeciv
|
||
Name[pt]=Freeciv
|
||
Name[ru]=Freeciv
|
||
Comment=Turn-based strategy game inspired by the history of human civilization
|
||
Comment[ca]=Joc d'estratègia inspirat en la història de la civilització humana
|
||
Comment[da]=Strategispil inspireret af den menneskelige civilisations historie
|
||
Comment[de]=Rundenbasiertes Strategiespiel, inspiriert durch die Geschichte der menschlichen Zivilisation
|
||
Comment[fi]=Ihmiskunnan historian inspiroima vuoropohjainen strategiapeli
|
||
Comment[nb]=Strategispill inspirert av historien til menneskelig sivilisasjon
|
||
Comment[pt]=Jogo de estratégia por turnos inspirado na História da civilização humana
|
||
Comment[ru]=Пошаговая стратегическая игра, вдохновлённая историей человеческой цивилизации
|
||
Comment[sv]=Turordningsbaserat strategispel inspirerat av den mänskliga historien
|
||
Exec=freeciv-gtk4x
|
||
Icon=freeciv-client
|
||
StartupNotify=true
|
||
Terminal=false
|
||
Type=Application
|
||
Categories=GTK;Game;StrategyGame;
|
||
Keywords=strategy;simulation;civilization;tiles;history;mankind;multiplayer;
|
bootstrap/org.freeciv.gtk4x.metainfo.xml.in | ||
---|---|---|
<?xml version="1.0" encoding="UTF-8"?>
|
||
<component type="desktop-application">
|
||
<name>Freeciv gtk4x client</name>
|
||
<id>org.freeciv.gtk4x</id>
|
||
<project_license>GPL-2.0-or-later</project_license>
|
||
<metadata_license>CC0</metadata_license>
|
||
<developer id="org.freeciv">
|
||
<name>Freeciv Team</name>
|
||
</developer>
|
||
<summary>Gtk4 based client for the Freeciv game</summary>
|
||
<description>
|
||
<p>
|
||
Freeciv is a Free and Open Source empire-building strategy game inspired by the history of human civilization. The game commences in prehistory and your
|
||
mission is to lead your tribe from the Stone Age to the Space Age...
|
||
</p>
|
||
<p>
|
||
This client for connecting to network games, or to launch local single-player games, is based on gtk4 widget set.
|
||
</p>
|
||
</description>
|
||
<launchable type="desktop-id">org.freeciv.gtk4x.desktop</launchable>
|
||
<url type="homepage">https://www.freeciv.org/</url>
|
||
<url type="bugtracker">https://osdn.net/projects/freeciv/ticket/</url>
|
||
<url type="faq">https://www.freeciv.org/wiki/FAQ</url>
|
||
<url type="donation">https://www.freeciv.org/donate.html</url>
|
||
<url type="translate">https://www.freeciv.org/wiki/Translations</url>
|
||
<url type="contact">https://www.freeciv.org/maillists.html</url>
|
||
<!-- flatpak does not understand these
|
||
<url type="vcs-browser">https://github.com/freeciv/freeciv/</url>
|
||
<url type="contribute">https://www.freeciv.org/wiki/How_to_Contribute</url>
|
||
-->
|
||
<releases>
|
||
[release]
|
||
</releases>
|
||
<content_rating type="oars-1.0">
|
||
<content_attribute id="social-chat">intense</content_attribute>
|
||
</content_rating>
|
||
<screenshots>
|
||
<screenshot type="default">
|
||
<image>https://files.freeciv.org/screenshots/3.1/client.gtk4-3.1.0-beta2.png</image>
|
||
</screenshot>
|
||
</screenshots>
|
||
<update_contact>freeciv-dev@freelists.org</update_contact>
|
||
</component>
|
bootstrap/org.freeciv.gtk4x.mp.desktop | ||
---|---|---|
[Desktop Entry]
|
||
Name=Freeciv modpack installer (gtk4x)
|
||
Name[ru]=Установщик модпаков Freeciv (gtk4x)
|
||
Comment=Download and install add-ons for Freeciv
|
||
Comment[ru]=Скачивайте и устанавливайте дополнения для Freeciv
|
||
Exec=freeciv-mp-gtk4x
|
||
Icon=freeciv-modpack
|
||
StartupNotify=true
|
||
Terminal=false
|
||
Type=Application
|
||
Categories=GTK;Game;StrategyGame;
|
||
Keywords=strategy;simulation;civilization;tiles;history;mankind;multiplayer;download;installer;
|
bootstrap/org.freeciv.gtk4x.mp.metainfo.xml.in | ||
---|---|---|
<?xml version="1.0" encoding="UTF-8"?>
|
||
<component type="desktop-application">
|
||
<name>Freeciv gtk-4+ modpack installer</name>
|
||
<id>org.freeciv.gtk4x.mp</id>
|
||
<project_license>GPL-2.0-or-later</project_license>
|
||
<metadata_license>CC0</metadata_license>
|
||
<developer id="org.freeciv">
|
||
<name>Freeciv Team</name>
|
||
</developer>
|
||
<summary>Gtk-4 based modpack installer for the Freeciv game</summary>
|
||
<description>
|
||
<p>
|
||
Freeciv is a Free and Open Source empire-building strategy game inspired by the history of human civilization. The game commences in prehistory and your
|
||
mission is to lead your tribe from the Stone Age to the Space Age...
|
||
</p>
|
||
<p>
|
||
Freeciv modpack utility can be used to automatically download and install custom rulesets, tilesets, soundsets, and maps for freeciv to use.
|
||
</p>
|
||
</description>
|
||
<launchable type="desktop-id">org.freeciv.gtk4x.mp.desktop</launchable>
|
||
<url type="homepage">https://www.freeciv.org/</url>
|
||
<url type="bugtracker">https://osdn.net/projects/freeciv/ticket/</url>
|
||
<url type="faq">https://www.freeciv.org/wiki/FAQ</url>
|
||
<url type="donation">https://www.freeciv.org/donate.html</url>
|
||
<url type="translate">https://www.freeciv.org/wiki/Translations</url>
|
||
<url type="contact">https://www.freeciv.org/maillists.html</url>
|
||
<!-- flatpak does not understand these
|
||
<url type="vcs-browser">https://github.com/freeciv/freeciv/</url>
|
||
<url type="contribute">https://www.freeciv.org/wiki/How_to_Contribute</url>
|
||
-->
|
||
<releases>
|
||
[release]
|
||
</releases>
|
||
<content_rating type="oars-1.0" />
|
||
<screenshots>
|
||
<screenshot type="default">
|
||
<image>https://files.freeciv.org/screenshots/3.0/modinst.gtk4-3.0.6.png</image>
|
||
</screenshot>
|
||
</screenshots>
|
||
<update_contact>freeciv-dev@freelists.org</update_contact>
|
||
</component>
|
client/gui-gtk-5.0/.gitignore | ||
---|---|---|
/Makefile.in
|
client/gui-gtk-5.0/Makefile.am | ||
---|---|---|
## Process this file with automake to produce Makefile.in
|
||
noinst_LTLIBRARIES = libgui-gtk5.la
|
||
AM_CPPFLAGS = \
|
||
-I$(srcdir)/.. \
|
||
-I$(srcdir)/../include \
|
||
-I$(top_srcdir)/utility \
|
||
-I$(top_srcdir)/common \
|
||
-I$(top_srcdir)/common/aicore \
|
||
-I$(top_srcdir)/common/networking \
|
||
-I$(top_srcdir)/common/scriptcore \
|
||
-I$(srcdir)/../agents \
|
||
-I$(srcdir)/../luascript \
|
||
-I$(top_srcdir)/dependencies/tinycthread \
|
||
-I$(top_srcdir)/gen_headers/enums \
|
||
$(gui_gtk5_cflags) $(SOUND_CFLAGS)
|
||
libgui_gtk5_la_SOURCES = \
|
||
action_dialog.c \
|
||
canvas.c \
|
||
canvas.h \
|
||
chatline.h \
|
||
chatline.c \
|
||
choice_dialog.c \
|
||
choice_dialog.h \
|
||
citizensinfo.c \
|
||
citizensinfo.h \
|
||
citydlg.c \
|
||
citydlg.h \
|
||
cityrep.c \
|
||
cityrep.h \
|
||
cma_fe.c \
|
||
cma_fe.h \
|
||
colors.c \
|
||
colors.h \
|
||
connectdlg.c \
|
||
connectdlg.h \
|
||
dialogs.c \
|
||
dialogs.h \
|
||
diplodlg.c \
|
||
diplodlg.h \
|
||
editgui.c \
|
||
editgui.h \
|
||
editprop.c \
|
||
editprop.h \
|
||
finddlg.c \
|
||
finddlg.h \
|
||
gamedlgs.c \
|
||
gamedlgs.h \
|
||
gotodlg.c \
|
||
gotodlg.h \
|
||
graphics.c \
|
||
graphics.h \
|
||
gui_main.c \
|
||
gui_main.h \
|
||
gui_stuff.c \
|
||
gui_stuff.h \
|
||
happiness.c \
|
||
happiness.h \
|
||
helpdlg.c \
|
||
helpdlg.h \
|
||
infradlg.c \
|
||
infradlg.h \
|
||
inputdlg.c \
|
||
inputdlg.h \
|
||
inteldlg.c \
|
||
inteldlg.h \
|
||
luaconsole.c \
|
||
luaconsole.h \
|
||
mapctrl.c \
|
||
mapctrl.h \
|
||
mapview.c \
|
||
mapview.h \
|
||
menu.c \
|
||
menu.h \
|
||
messagedlg.c \
|
||
messagedlg.h \
|
||
messagewin.c \
|
||
messagewin.h \
|
||
optiondlg.c \
|
||
optiondlg.h \
|
||
pages.c \
|
||
pages.h \
|
||
plrdlg.c \
|
||
plrdlg.h \
|
||
rallypointdlg.c \
|
||
rallypointdlg.h \
|
||
ratesdlg.h \
|
||
repodlgs.c \
|
||
repodlgs.h \
|
||
soundset_dlg.c \
|
||
spaceshipdlg.c \
|
||
spaceshipdlg.h \
|
||
sprite.c \
|
||
sprite.h \
|
||
theme_dlg.c \
|
||
themes.c \
|
||
tileset_dlg.c \
|
||
transportdlg.c \
|
||
transportdlg.h \
|
||
unitselextradlg.c \
|
||
unitselextradlg.h \
|
||
unitselunitdlg.c \
|
||
unitselunitdlg.h \
|
||
unitselect.h \
|
||
unitselect.c \
|
||
voteinfo_bar.c \
|
||
voteinfo_bar.h \
|
||
wldlg.c \
|
||
wldlg.h
|
||
libgui_gtk5_la_LIBADD = -lm
|
client/gui-gtk-5.0/action_dialog.c | ||
---|---|---|
/***********************************************************************
|
||
Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2, or (at your option)
|
||
any later version.
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
***********************************************************************/
|
||
#ifdef HAVE_CONFIG_H
|
||
#include <fc_config.h>
|
||
#endif
|
||
#include <gtk/gtk.h>
|
||
/* utility */
|
||
#include "astring.h"
|
||
#include "support.h"
|
||
/* common */
|
||
#include "actions.h"
|
||
#include "game.h"
|
||
#include "traderoutes.h"
|
||
#include "movement.h"
|
||
#include "research.h"
|
||
#include "unit.h"
|
||
#include "unitlist.h"
|
||
/* client */
|
||
#include "dialogs_g.h"
|
||
#include "chatline.h"
|
||
#include "choice_dialog.h"
|
||
#include "client_main.h"
|
||
#include "climisc.h"
|
||
#include "connectdlg_common.h"
|
||
#include "control.h"
|
||
#include "gui_main.h"
|
||
#include "gui_stuff.h"
|
||
#include "mapview.h"
|
||
#include "packhand.h"
|
||
#include "text.h"
|
||
/* client/gui-gtk-5.0 */
|
||
#include "citydlg.h"
|
||
#include "dialogs.h"
|
||
#include "unitselextradlg.h"
|
||
#include "unitselunitdlg.h"
|
||
#include "wldlg.h"
|
||
/* Locations for non action enabler controlled buttons. */
|
||
#define BUTTON_NEW_UNIT_TGT (ACTION_COUNT + 1)
|
||
#define BUTTON_NEW_EXTRA_TGT (BUTTON_NEW_UNIT_TGT + 1)
|
||
#define BUTTON_LOCATION (BUTTON_NEW_EXTRA_TGT + 1)
|
||
#define BUTTON_WAIT (BUTTON_LOCATION + 1)
|
||
#define BUTTON_CANCEL (BUTTON_WAIT + 1)
|
||
#define BUTTON_COUNT (BUTTON_CANCEL + 1)
|
||
#define BUTTON_NOT_THERE -1
|
||
static GtkWidget *act_sel_dialog;
|
||
static int action_button_map[BUTTON_COUNT];
|
||
static int actor_unit_id;
|
||
static int target_ids[ATK_COUNT];
|
||
static int target_extra_id;
|
||
static bool is_more_user_input_needed = FALSE;
|
||
static bool did_not_decide = FALSE;
|
||
static bool action_selection_restart = FALSE;
|
||
static GtkWidget *spy_tech_shell;
|
||
static GtkWidget *spy_sabotage_shell;
|
||
/* A structure to hold parameters for actions inside the GUI instead of
|
||
* storing the needed data in a global variable. */
|
||
struct action_data {
|
||
action_id act_id;
|
||
int actor_unit_id;
|
||
int target_city_id;
|
||
int target_unit_id;
|
||
int target_tile_id;
|
||
int target_building_id;
|
||
int target_tech_id;
|
||
int target_extra_id;
|
||
};
|
||
/* TODO: Maybe this should be in the dialog itself? */
|
||
static struct action_data *act_sel_dialog_data;
|
||
#define FC_TYPE_ACTION_ROW (fc_action_row_get_type())
|
||
G_DECLARE_FINAL_TYPE(FcActionRow, fc_action_row, FC, ACTION_ROW, GObject)
|
||
struct _FcActionRow
|
||
{
|
||
GObject parent_instance;
|
||
char *name;
|
||
int id;
|
||
};
|
||
struct _FcActionRowClass
|
||
{
|
||
GObjectClass parent_class;
|
||
};
|
||
G_DEFINE_TYPE(FcActionRow, fc_action_row, G_TYPE_OBJECT)
|
||
/**********************************************************************//**
|
||
Finalizing method for FcActionRow
|
||
**************************************************************************/
|
||
static void fc_action_row_finalize(GObject *gobject)
|
||
{
|
||
FcActionRow *row = FC_ACTION_ROW(gobject);
|
||
free(row->name);
|
||
row->name = nullptr;
|
||
G_OBJECT_CLASS(fc_action_row_parent_class)->finalize(gobject);
|
||
}
|
||
/**********************************************************************//**
|
||
Initialization method for FcActionRow class
|
||
**************************************************************************/
|
||
static void
|
||
fc_action_row_class_init(FcActionRowClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||
object_class->finalize = fc_action_row_finalize;
|
||
}
|
||
/**********************************************************************//**
|
||
Initialization method for FcActionRow
|
||
**************************************************************************/
|
||
static void
|
||
fc_action_row_init(FcActionRow *self)
|
||
{
|
||
self->name = nullptr;
|
||
}
|
||
/**********************************************************************//**
|
||
FcActionRow creation method
|
||
**************************************************************************/
|
||
static FcActionRow *fc_action_row_new(void)
|
||
{
|
||
FcActionRow *result;
|
||
result = g_object_new(FC_TYPE_ACTION_ROW, nullptr);
|
||
return result;
|
||
}
|
||
/**********************************************************************//**
|
||
Create a new action data structure that can be stored in the
|
||
dialogs.
|
||
**************************************************************************/
|
||
static struct action_data *act_data(action_id act_id,
|
||
int actor_id,
|
||
int target_city_id,
|
||
int target_unit_id,
|
||
int target_tile_id,
|
||
int target_building_id,
|
||
int target_tech_id,
|
||
int tgt_extra_id)
|
||
{
|
||
struct action_data *data = fc_malloc(sizeof(*data));
|
||
data->act_id = act_id;
|
||
data->actor_unit_id = actor_id;
|
||
data->target_city_id = target_city_id;
|
||
data->target_unit_id = target_unit_id;
|
||
data->target_tile_id = target_tile_id;
|
||
data->target_building_id = target_building_id;
|
||
data->target_tech_id = target_tech_id;
|
||
data->target_extra_id = tgt_extra_id;
|
||
return data;
|
||
}
|
||
/**********************************************************************//**
|
||
Move the queue of units that need user input forward unless the current
|
||
unit is going to need more input.
|
||
**************************************************************************/
|
||
static void diplomat_queue_handle_primary(void)
|
||
{
|
||
if (!is_more_user_input_needed) {
|
||
/* The client isn't waiting for information for any unanswered follow
|
||
* up questions. */
|
||
struct unit *actor_unit;
|
||
if ((actor_unit = game_unit_by_number(actor_unit_id))) {
|
||
/* The action selection dialog wasn't closed because the actor unit
|
||
* was lost. */
|
||
/* The probabilities didn't just disappear, right? */
|
||
fc_assert_action(actor_unit->client.act_prob_cache,
|
||
client_unit_init_act_prob_cache(actor_unit));
|
||
FC_FREE(actor_unit->client.act_prob_cache);
|
||
}
|
||
if (action_selection_restart) {
|
||
/* The action selection dialog was closed but only so it can be
|
||
* redrawn with fresh data. */
|
||
action_selection_restart = FALSE;
|
||
} else {
|
||
/* The action selection process is over, at least for now. */
|
||
action_selection_no_longer_in_progress(actor_unit_id);
|
||
}
|
||
if (did_not_decide) {
|
||
/* The action selection dialog was closed but the player didn't
|
||
* decide what the unit should do. */
|
||
/* Reset so the next action selection dialog does the right thing. */
|
||
did_not_decide = FALSE;
|
||
} else {
|
||
/* An action, or no action at all, was selected. */
|
||
action_decision_clear_want(actor_unit_id);
|
||
action_selection_next_in_focus(actor_unit_id);
|
||
}
|
||
}
|
||
}
|
||
/**********************************************************************//**
|
||
Move the queue of units that need user input forward since the
|
||
current unit doesn't require the extra input any more.
|
||
**************************************************************************/
|
||
static void diplomat_queue_handle_secondary(void)
|
||
{
|
||
/* Stop waiting. Move on to the next queued unit. */
|
||
is_more_user_input_needed = FALSE;
|
||
diplomat_queue_handle_primary();
|
||
}
|
||
/**********************************************************************//**
|
||
Let the non shared client code know that the action selection process
|
||
no longer is in progress for the specified unit.
|
||
This allows the client to clean up any client specific assumptions.
|
||
**************************************************************************/
|
||
void action_selection_no_longer_in_progress_gui_specific(int actor_id)
|
||
{
|
||
/* Stop assuming the answer to a follow up question will arrive. */
|
||
is_more_user_input_needed = FALSE;
|
||
}
|
||
/**********************************************************************//**
|
||
Get the non targeted version of an action so it, if enabled, can appear
|
||
in the target selection dialog.
|
||
**************************************************************************/
|
||
static action_id get_non_targeted_action_id(action_id tgt_action_id)
|
||
{
|
||
/* Don't add an action mapping here unless the non targeted version is
|
||
* selectable in the targeted version's target selection dialog. */
|
||
switch ((enum gen_action)tgt_action_id) {
|
||
case ACTION_SPY_TARGETED_SABOTAGE_CITY:
|
||
return ACTION_SPY_SABOTAGE_CITY;
|
||
case ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC:
|
||
return ACTION_SPY_SABOTAGE_CITY_ESC;
|
||
case ACTION_SPY_TARGETED_STEAL_TECH:
|
||
return ACTION_SPY_STEAL_TECH;
|
||
case ACTION_SPY_TARGETED_STEAL_TECH_ESC:
|
||
return ACTION_SPY_STEAL_TECH_ESC;
|
||
default:
|
||
/* No non targeted version found. */
|
||
return ACTION_NONE;
|
||
}
|
||
}
|
||
/**********************************************************************//**
|
||
Get the production targeted version of an action so it, if enabled, can
|
||
appear in the target selection dialog.
|
||
**************************************************************************/
|
||
static action_id get_production_targeted_action_id(action_id tgt_action_id)
|
||
{
|
||
/* Don't add an action mapping here unless the non targeted version is
|
||
* selectable in the targeted version's target selection dialog. */
|
||
switch ((enum gen_action)tgt_action_id) {
|
||
case ACTION_SPY_TARGETED_SABOTAGE_CITY:
|
||
return ACTION_SPY_SABOTAGE_CITY_PRODUCTION;
|
||
case ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC:
|
||
return ACTION_SPY_SABOTAGE_CITY_PRODUCTION_ESC;
|
||
case ACTION_STRIKE_BUILDING:
|
||
return ACTION_STRIKE_PRODUCTION;
|
||
default:
|
||
/* No non targeted version found. */
|
||
return ACTION_NONE;
|
||
}
|
||
}
|
||
/**********************************************************************//**
|
||
User selected an action from the choice dialog and the action has no
|
||
special needs.
|
||
**************************************************************************/
|
||
static void simple_action_callback(GtkWidget *w, gpointer data)
|
||
{
|
||
int actor_id, target_id, sub_target;
|
||
struct action *paction;
|
||
struct action_data *args = act_sel_dialog_data;
|
||
bool failed = FALSE;
|
||
/* Data */
|
||
args->act_id = GPOINTER_TO_INT(data);
|
||
paction = action_by_number(args->act_id);
|
||
/* Actor */
|
||
fc_assert(action_get_actor_kind(paction) == AAK_UNIT);
|
||
actor_id = args->actor_unit_id;
|
||
if (NULL == game_unit_by_number(actor_id)) {
|
||
/* Probably dead. */
|
||
failed = TRUE;
|
||
}
|
||
/* Target */
|
||
target_id = IDENTITY_NUMBER_ZERO;
|
||
switch (action_get_target_kind(paction)) {
|
||
case ATK_CITY:
|
||
target_id = args->target_city_id;
|
||
if (NULL == game_city_by_number(target_id)) {
|
||
/* Probably destroyed. */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ATK_UNIT:
|
||
target_id = args->target_unit_id;
|
||
if (NULL == game_unit_by_number(target_id)) {
|
||
/* Probably dead. */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ATK_STACK:
|
||
case ATK_TILE:
|
||
case ATK_EXTRAS:
|
||
target_id = args->target_tile_id;
|
||
if (NULL == index_to_tile(&(wld.map), target_id)) {
|
||
/* TODO: Should this be possible at all? If not: add assertion. */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ATK_SELF:
|
||
target_id = IDENTITY_NUMBER_ZERO;
|
||
break;
|
||
case ATK_COUNT:
|
||
fc_assert(action_get_target_kind(paction) != ATK_COUNT);
|
||
failed = TRUE;
|
||
}
|
||
/* Sub target. */
|
||
sub_target = NO_TARGET;
|
||
if (paction->target_complexity != ACT_TGT_COMPL_SIMPLE) {
|
||
switch (action_get_sub_target_kind(paction)) {
|
||
case ASTK_BUILDING:
|
||
sub_target = args->target_building_id;
|
||
if (NULL == improvement_by_number(sub_target)) {
|
||
/* Did the ruleset change? */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ASTK_TECH:
|
||
sub_target = args->target_tech_id;
|
||
if (NULL == valid_advance_by_number(sub_target)) {
|
||
/* Did the ruleset change? */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ASTK_EXTRA:
|
||
case ASTK_EXTRA_NOT_THERE:
|
||
/* TODO: Validate if the extra is there? */
|
||
sub_target = args->target_extra_id;
|
||
if (NULL == extra_by_number(sub_target)) {
|
||
/* Did the ruleset change? */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ASTK_NONE:
|
||
case ASTK_COUNT:
|
||
/* Shouldn't happen. */
|
||
fc_assert(action_get_sub_target_kind(paction) != ASTK_NONE);
|
||
failed = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
/* Send request. */
|
||
if (!failed) {
|
||
request_do_action(paction->id, actor_id, target_id, sub_target, "");
|
||
}
|
||
/* Clean up. */
|
||
choice_dialog_destroy(act_sel_dialog);
|
||
/* No follow up questions. */
|
||
act_sel_dialog_data = NULL;
|
||
FC_FREE(args);
|
||
}
|
||
/**********************************************************************//**
|
||
User selected an action from the choice dialog that needs details from
|
||
the server.
|
||
**************************************************************************/
|
||
static void request_action_details_callback(GtkWidget *w, gpointer data)
|
||
{
|
||
int actor_id, target_id;
|
||
struct action *paction;
|
||
struct action_data *args = act_sel_dialog_data;
|
||
bool failed = FALSE;
|
||
/* Data */
|
||
args->act_id = GPOINTER_TO_INT(data);
|
||
paction = action_by_number(args->act_id);
|
||
/* Actor */
|
||
fc_assert(action_get_actor_kind(paction) == AAK_UNIT);
|
||
actor_id = args->actor_unit_id;
|
||
if (NULL == game_unit_by_number(actor_id)) {
|
||
/* Probably dead. */
|
||
failed = TRUE;
|
||
}
|
||
/* Target */
|
||
target_id = IDENTITY_NUMBER_ZERO;
|
||
switch (action_get_target_kind(paction)) {
|
||
case ATK_CITY:
|
||
target_id = args->target_city_id;
|
||
if (NULL == game_city_by_number(target_id)) {
|
||
/* Probably destroyed. */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ATK_UNIT:
|
||
target_id = args->target_unit_id;
|
||
if (NULL == game_unit_by_number(target_id)) {
|
||
/* Probably dead. */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ATK_STACK:
|
||
case ATK_TILE:
|
||
case ATK_EXTRAS:
|
||
target_id = args->target_tile_id;
|
||
if (NULL == index_to_tile(&(wld.map), target_id)) {
|
||
/* TODO: Should this be possible at all? If not: add assertion. */
|
||
failed = TRUE;
|
||
}
|
||
break;
|
||
case ATK_SELF:
|
||
target_id = IDENTITY_NUMBER_ZERO;
|
||
break;
|
||
case ATK_COUNT:
|
||
fc_assert(action_get_target_kind(paction) != ATK_COUNT);
|
||
failed = TRUE;
|
||
}
|
||
/* Send request. */
|
||
if (!failed) {
|
||
request_action_details(paction->id, actor_id, target_id);
|
||
}
|
||
/* Wait for the server's reply before moving on to the next unit that
|
||
* needs to know what action to take. */
|
||
is_more_user_input_needed = TRUE;
|
||
/* Clean up. */
|
||
choice_dialog_destroy(act_sel_dialog);
|
||
/* No client side follow up questions. */
|
||
act_sel_dialog_data = NULL;
|
||
FC_FREE(args);
|
||
}
|
||
/**********************************************************************//**
|
||
User selected build city from the choice dialog
|
||
**************************************************************************/
|
||
static void found_city_callback(GtkWidget *w, gpointer data)
|
||
{
|
||
struct action_data *args = act_sel_dialog_data;
|
||
dsend_packet_city_name_suggestion_req(&client.conn,
|
||
args->actor_unit_id);
|
||
choice_dialog_destroy(act_sel_dialog);
|
||
free(args);
|
||
}
|
||
/**********************************************************************//**
|
||
User selected "Upgrade Unit" from choice dialog.
|
||
**************************************************************************/
|
||
static void upgrade_callback(GtkWidget *w, gpointer data)
|
||
{
|
||
struct unit *punit;
|
||
struct action_data *args = act_sel_dialog_data;
|
||
if ((punit = game_unit_by_number(args->actor_unit_id))
|
||
&& NULL != game_city_by_number(args->target_city_id)) {
|
||
struct unit_list *as_list;
|
||
as_list = unit_list_new();
|
||
unit_list_append(as_list, punit);
|
||
popup_upgrade_dialog(as_list);
|
||
unit_list_destroy(as_list);
|
||
}
|
||
choice_dialog_destroy(act_sel_dialog);
|
||
free(args);
|
||
}
|
||
/**********************************************************************//**
|
||
User responded to bribe unit dialog
|
||
**************************************************************************/
|
||
static void bribe_unit_response(GtkWidget *w, gint response, gpointer data)
|
||
{
|
||
struct action_data *args = (struct action_data *)data;
|
||
if (response == GTK_RESPONSE_YES) {
|
||
request_do_action(args->act_id, args->actor_unit_id,
|
||
args->target_unit_id, 0, "");
|
||
}
|
||
gtk_window_destroy(GTK_WINDOW(w));
|
||
free(args);
|
||
/* The user have answered the follow up question. Move on. */
|
||
diplomat_queue_handle_secondary();
|
||
}
|
||
/**********************************************************************//**
|
||
User responded to bribe stack dialog
|
||
**************************************************************************/
|
||
static void bribe_stack_response(GtkWidget *w, gint response, gpointer data)
|
||
{
|
||
struct action_data *args = (struct action_data *)data;
|
||
if (response == GTK_RESPONSE_YES) {
|
||
request_do_action(args->act_id, args->actor_unit_id,
|
||
args->target_tile_id, 0, "");
|
||
}
|
||
gtk_window_destroy(GTK_WINDOW(w));
|
||
free(args);
|
||
/* The user have answered the follow up question. Move on. */
|
||
diplomat_queue_handle_secondary();
|
||
}
|
||
/**********************************************************************//**
|
||
Popup unit bribe dialog
|
||
**************************************************************************/
|
||
void popup_bribe_unit_dialog(struct unit *actor, struct unit *punit, int cost,
|
||
const struct action *paction)
|
||
{
|
||
GtkWidget *shell;
|
||
char buf[1024];
|
||
fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
|
||
"Treasury contains %d gold.",
|
||
client_player()->economic.gold),
|
||
client_player()->economic.gold);
|
||
if (cost <= client_player()->economic.gold) {
|
||
shell = gtk_message_dialog_new(NULL, 0,
|
||
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
|
||
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
|
||
PL_("Bribe unit for %d gold?\n%s",
|
||
"Bribe unit for %d gold?\n%s", cost), cost, buf);
|
||
gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
|
||
setup_dialog(shell, toplevel);
|
||
} else {
|
||
shell = gtk_message_dialog_new(NULL, 0,
|
||
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
|
||
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
|
||
PL_("Bribing the unit costs %d gold.\n%s",
|
||
"Bribing the unit costs %d gold.\n%s", cost), cost, buf);
|
||
gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
|
||
setup_dialog(shell, toplevel);
|
||
}
|
||
gtk_window_present(GTK_WINDOW(shell));
|
||
g_signal_connect(shell, "response", G_CALLBACK(bribe_unit_response),
|
||
act_data(paction->id, actor->id,
|
||
0, punit->id, 0,
|
||
0, 0, 0));
|
||
}
|
||
/**********************************************************************//**
|
||
Popup stack bribe dialog
|
||
**************************************************************************/
|
||
void popup_bribe_stack_dialog(struct unit *actor, struct tile *ptile, int cost,
|
||
const struct action *paction)
|
||
{
|
||
GtkWidget *shell;
|
||
char buf[1024];
|
||
fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
|
||
"Treasury contains %d gold.",
|
||
client_player()->economic.gold),
|
||
client_player()->economic.gold);
|
||
if (cost <= client_player()->economic.gold) {
|
||
shell = gtk_message_dialog_new(NULL, 0,
|
||
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
|
||
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
|
||
PL_("Bribe unit stack for %d gold?\n%s",
|
||
"Bribe unit stack for %d gold?\n%s", cost), cost, buf);
|
||
gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Stack"));
|
||
setup_dialog(shell, toplevel);
|
||
} else {
|
||
shell = gtk_message_dialog_new(NULL, 0,
|
||
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
|
||
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
|
||
PL_("Bribing units costs %d gold.\n%s",
|
||
"Bribing units costs %d gold.\n%s", cost), cost, buf);
|
||
gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
|
||
setup_dialog(shell, toplevel);
|
||
}
|
||
gtk_window_present(GTK_WINDOW(shell));
|
||
g_signal_connect(shell, "response", G_CALLBACK(bribe_stack_response),
|
||
act_data(paction->id, actor->id,
|
||
0, 0, ptile->index,
|
||
0, 0, 0));
|
||
}
|
||
/**********************************************************************//**
|
||
User responded to steal advances dialog
|
||
**************************************************************************/
|
||
static void spy_advances_response(GtkWidget *w, gint response,
|
||
gpointer data)
|
||
{
|
||
struct action_data *args = (struct action_data *)data;
|
||
if (response == GTK_RESPONSE_ACCEPT && args->target_tech_id > 0) {
|
||
if (NULL != game_unit_by_number(args->actor_unit_id)
|
||
&& NULL != game_city_by_number(args->target_city_id)) {
|
||
if (args->target_tech_id == A_UNSET) {
|
||
/* This is the untargeted version. */
|
||
request_do_action(get_non_targeted_action_id(args->act_id),
|
||
args->actor_unit_id, args->target_city_id,
|
||
args->target_tech_id, "");
|
||
} else {
|
||
/* This is the targeted version. */
|
||
request_do_action(args->act_id,
|
||
args->actor_unit_id, args->target_city_id,
|
||
args->target_tech_id, "");
|
||
}
|
||
}
|
||
}
|
||
gtk_window_destroy(GTK_WINDOW(spy_tech_shell));
|
||
spy_tech_shell = NULL;
|
||
free(data);
|
||
/* The user have answered the follow up question. Move on. */
|
||
diplomat_queue_handle_secondary();
|
||
}
|
||
/**********************************************************************//**
|
||
User selected entry in steal advances dialog
|
||
**************************************************************************/
|
||
static void spy_advances_callback(GtkSelectionModel *self,
|
||
guint position,
|
||
guint n_items,
|
||
gpointer data)
|
||
{
|
||
struct action_data *args = (struct action_data *)data;
|
||
FcActionRow *row = gtk_single_selection_get_selected_item(
|
||
GTK_SINGLE_SELECTION(self));
|
||
if (row != NULL) {
|
||
args->target_tech_id = row->id;
|
||
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
|
||
GTK_RESPONSE_ACCEPT, TRUE);
|
||
} else {
|
||
args->target_tech_id = 0;
|
||
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
|
||
GTK_RESPONSE_ACCEPT, FALSE);
|
||
}
|
||
}
|
||
/**********************************************************************//**
|
||
Action table cell bind function
|
||
**************************************************************************/
|
||
static void action_factory_bind(GtkSignalListItemFactory *self,
|
||
GtkListItem *list_item,
|
||
gpointer user_data)
|
||
{
|
||
FcActionRow *row;
|
||
row = gtk_list_item_get_item(list_item);
|
||
gtk_label_set_text(GTK_LABEL(gtk_list_item_get_child(list_item)),
|
||
row->name);
|
||
}
|
||
/**********************************************************************//**
|
||
Action table cell setup function
|
||
**************************************************************************/
|
||
static void action_factory_setup(GtkSignalListItemFactory *self,
|
||
GtkListItem *list_item,
|
||
gpointer user_data)
|
||
{
|
||
gtk_list_item_set_child(list_item, gtk_label_new(""));
|
||
}
|
||
/**********************************************************************//**
|
||
Create spy's tech stealing dialog
|
||
**************************************************************************/
|
||
static void create_advances_list(struct player *pplayer,
|
||
struct player *pvictim,
|
||
struct action_data *args)
|
||
{
|
||
GtkWidget *frame, *label, *vgrid;
|
||
GListStore *store;
|
||
GtkWidget *list;
|
||
GtkColumnViewColumn *column;
|
||
GtkListItemFactory *factory;
|
||
GtkSingleSelection *selection;
|
||
struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
|
||
spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
|
||
NULL, 0,
|
||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||
_("_Steal"), GTK_RESPONSE_ACCEPT,
|
||
NULL);
|
||
setup_dialog(spy_tech_shell, toplevel);
|
||
gtk_dialog_set_default_response(GTK_DIALOG(spy_tech_shell),
|
||
GTK_RESPONSE_ACCEPT);
|
||
frame = gtk_frame_new(_("Select Advance to Steal"));
|
||
gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell))), frame);
|
||
vgrid = gtk_grid_new();
|
||
gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
|
||
GTK_ORIENTATION_VERTICAL);
|
||
gtk_grid_set_row_spacing(GTK_GRID(vgrid), 6);
|
||
gtk_frame_set_child(GTK_FRAME(frame), vgrid);
|
||
store = g_list_store_new(FC_TYPE_ACTION_ROW);
|
||
selection = gtk_single_selection_new(G_LIST_MODEL(store));
|
||
list = gtk_column_view_new(GTK_SELECTION_MODEL(selection));
|
||
factory = gtk_signal_list_item_factory_new();
|
||
g_signal_connect(factory, "bind", G_CALLBACK(action_factory_bind),
|
||
nullptr);
|
||
g_signal_connect(factory, "setup", G_CALLBACK(action_factory_setup),
|
||
nullptr);
|
||
column = gtk_column_view_column_new(_("Tech"), factory);
|
||
gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
|
||
label = g_object_new(GTK_TYPE_LABEL,
|
||
"use-underline", TRUE,
|
||
"mnemonic-widget", list,
|
||
"label", _("_Advances:"),
|
||
"xalign", 0.0,
|
||
"yalign", 0.5,
|
||
NULL);
|
||
gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
|
||
gtk_grid_attach(GTK_GRID(vgrid), list, 0, 1, 1, 1);
|
||
/* Now populate the list */
|
||
if (pvictim) { /* You don't want to know what lag can do -- Syela */
|
||
const struct research *presearch = research_get(pplayer);
|
||
const struct research *vresearch = research_get(pvictim);
|
||
GValue value = { 0, };
|
||
advance_index_iterate(A_FIRST, i) {
|
||
if (research_invention_gettable(presearch, i,
|
||
game.info.tech_steal_allow_holes)
|
||
&& research_invention_state(vresearch, i) == TECH_KNOWN
|
||
&& research_invention_state(presearch, i) != TECH_KNOWN) {
|
||
FcActionRow *row = fc_action_row_new();
|
||
row->name = fc_strdup(research_advance_name_translation(presearch, i));
|
||
row->id = i;
|
||
g_list_store_append(store, row);
|
||
g_object_unref(row);
|
||
}
|
||
} advance_index_iterate_end;
|
||
if (action_prob_possible(actor_unit->client.act_prob_cache[
|
||
get_non_targeted_action_id(args->act_id)])) {
|
||
FcActionRow *row = fc_action_row_new();
|
||
{
|
||
struct astring str = ASTRING_INIT;
|
||
/* TRANS: %s is a unit name, e.g., Spy */
|
||
astr_set(&str, _("At %s's Discretion"),
|
||
unit_name_translation(actor_unit));
|
||
g_value_set_string(&value, astr_str(&str));
|
||
row->name = fc_strdup(astr_str(&str));
|
||
astr_free(&str);
|
||
}
|
||
row->id = A_UNSET;
|
||
g_list_store_append(store, row);
|
||
g_object_unref(row);
|
||
}
|
||
}
|
||
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
|
||
GTK_RESPONSE_ACCEPT, FALSE);
|
||
gtk_widget_set_visible(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell)),
|
||
TRUE);
|
||
g_signal_connect(selection, "selection-changed",
|
||
G_CALLBACK(spy_advances_callback), args);
|
||
g_signal_connect(spy_tech_shell, "response",
|
||
G_CALLBACK(spy_advances_response), args);
|
||
args->target_tech_id = 0;
|
||
}
|
||
/**********************************************************************//**
|
||
User has responded to spy's sabotage building dialog
|
||
**************************************************************************/
|
||
static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
|
||
{
|
||
struct action_data *args = (struct action_data *)data;
|
||
if (response == GTK_RESPONSE_ACCEPT && args->target_building_id > -2) {
|
||
if (NULL != game_unit_by_number(args->actor_unit_id)
|
||
&& NULL != game_city_by_number(args->target_city_id)) {
|
||
if (args->target_building_id == B_LAST) {
|
||
/* This is the untargeted version. */
|
||
request_do_action(get_non_targeted_action_id(args->act_id),
|
||
args->actor_unit_id,
|
||
args->target_city_id,
|
||
args->target_building_id, "");
|
||
} else if (args->target_building_id == -1) {
|
||
/* This is the city production version. */
|
||
request_do_action(get_production_targeted_action_id(args->act_id),
|
||
args->actor_unit_id,
|
||
args->target_city_id,
|
||
args->target_building_id, "");
|
||
} else {
|
||
/* This is the targeted version. */
|
||
request_do_action(args->act_id,
|
||
args->actor_unit_id,
|
||
args->target_city_id,
|
||
args->target_building_id, "");
|
||
}
|
||
}
|
||
}
|
||
gtk_window_destroy(GTK_WINDOW(spy_sabotage_shell));
|
||
spy_sabotage_shell = NULL;
|
||
free(args);
|
||
/* The user have answered the follow up question. Move on. */
|
||
diplomat_queue_handle_secondary();
|
||
}
|
||
/**********************************************************************//**
|
||
User has selected new building from spy's sabotage dialog
|
||
**************************************************************************/
|
||
static void spy_improvements_callback(GtkSelectionModel *self,
|
||
guint position,
|
||
guint n_items,
|
||
gpointer data)
|
||
{
|
||
struct action_data *args = (struct action_data *)data;
|
||
FcActionRow *row = gtk_single_selection_get_selected_item(
|
||
GTK_SINGLE_SELECTION(self));
|
||
if (row != NULL) {
|
||
args->target_building_id = row->id;
|
||
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
|
||
GTK_RESPONSE_ACCEPT, TRUE);
|
||
} else {
|
||
args->target_building_id = -2;
|
||
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
|
||
GTK_RESPONSE_ACCEPT, FALSE);
|
||
}
|
||
}
|
||
/**********************************************************************//**
|
||
Creates spy's building sabotaging dialog
|
||
**************************************************************************/
|
||
static void create_improvements_list(struct player *pplayer,
|
||
struct city *pcity,
|
||
struct action_data *args)
|
||
{
|
||
GtkWidget *frame, *label, *vgrid;
|
||
GListStore *store;
|
||
GtkWidget *list;
|
||
GtkColumnViewColumn *column;
|
||
GtkListItemFactory *factory;
|
||
GtkSingleSelection *selection;
|
||
struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
|
||
spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
|
||
NULL, 0,
|
||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||
_("_Sabotage"), GTK_RESPONSE_ACCEPT,
|
||
NULL);
|
||
setup_dialog(spy_sabotage_shell, toplevel);
|
||
gtk_dialog_set_default_response(GTK_DIALOG(spy_sabotage_shell),
|
||
GTK_RESPONSE_ACCEPT);
|
||
frame = gtk_frame_new(_("Select Improvement to Sabotage"));
|
||
gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(spy_sabotage_shell))), frame);
|
||
vgrid = gtk_grid_new();
|
||
gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
|
||
GTK_ORIENTATION_VERTICAL);
|
||
gtk_grid_set_row_spacing(GTK_GRID(vgrid), 6);
|
||
gtk_frame_set_child(GTK_FRAME(frame), vgrid);
|
||
store = g_list_store_new(FC_TYPE_ACTION_ROW);
|
||
selection = gtk_single_selection_new(G_LIST_MODEL(store));
|
||
list = gtk_column_view_new(GTK_SELECTION_MODEL(selection));
|
||
factory = gtk_signal_list_item_factory_new();
|
||
g_signal_connect(factory, "bind", G_CALLBACK(action_factory_bind),
|
||
nullptr);
|
||
g_signal_connect(factory, "setup", G_CALLBACK(action_factory_setup),
|
||
nullptr);
|
||
column = gtk_column_view_column_new(_("Improvement"), factory);
|
||
gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
|
||
label = g_object_new(GTK_TYPE_LABEL,
|
||
"use-underline", TRUE,
|
||
"mnemonic-widget", list,
|
||
"label", _("_Improvements:"),
|
||
"xalign", 0.0,
|
||
"yalign", 0.5,
|
||
NULL);
|
||
gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
|
||
gtk_grid_attach(GTK_GRID(vgrid), list, 0, 1, 1, 1);
|
||
/* Now populate the list */
|
||
if (action_prob_possible(actor_unit->client.act_prob_cache[
|
||
get_production_targeted_action_id(
|
||
args->act_id)])) {
|
||
FcActionRow *row = fc_action_row_new();
|
||
row->name = fc_strdup(_("City Production"));
|
||
row->id = -1;
|
||
g_list_store_append(store, row);
|
||
g_object_unref(row);
|
||
}
|
||
city_built_iterate(pcity, pimprove) {
|
||
if (pimprove->sabotage > 0) {
|
||
FcActionRow *row = fc_action_row_new();
|
||
row->name = fc_strdup(city_improvement_name_translation(pcity, pimprove));
|
||
row->id = improvement_number(pimprove);
|
||
g_list_store_append(store, row);
|
||
g_object_unref(row);
|
||
}
|
||
} city_built_iterate_end;
|
||
if (action_prob_possible(actor_unit->client.act_prob_cache[
|
||
get_non_targeted_action_id(args->act_id)])) {
|
||
struct astring str = ASTRING_INIT;
|
||
FcActionRow *row = fc_action_row_new();
|
||
/* TRANS: %s is a unit name, e.g., Spy */
|
||
astr_set(&str, _("At %s's Discretion"),
|
||
unit_name_translation(actor_unit));
|
||
row->name = fc_strdup(astr_str(&str));
|
||
row->id = B_LAST;
|
||
g_list_store_append(store, row);
|
||
g_object_unref(row);
|
||
astr_free(&str);
|
||
}
|
||
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
|
||
GTK_RESPONSE_ACCEPT, FALSE);
|