1 #include "config.h"
2 #include "game.h"
3 #include <gtk/gtk.h>
4 #include <string.h>
5 #include <glib.h>
6
7 #include "game-rules.h"
8 #include "game.h"
9
10 static void game_rules_init(GameRules * sg, gboolean show_all_rules);
11 static void verify_island_discovery_bonus(GtkButton * button,
12 gpointer user_data);
13
dice_deck_toggled_callback(GtkToggleButton * dice_deck,gpointer user_data)14 static void dice_deck_toggled_callback(GtkToggleButton * dice_deck,
15 gpointer user_data)
16 {
17 GameRules *gr = user_data;
18 gtk_widget_set_sensitive(GTK_WIDGET(gr->num_dice_decks),
19 gtk_toggle_button_get_active(dice_deck));
20 gtk_widget_set_sensitive(GTK_WIDGET(gr->num_removed_dice_cards),
21 gtk_toggle_button_get_active(dice_deck));
22 }
23
24 /* Register the class */
game_rules_get_type(void)25 GType game_rules_get_type(void)
26 {
27 static GType gp_type = 0;
28
29 if (!gp_type) {
30 static const GTypeInfo gp_info = {
31 sizeof(GameRulesClass),
32 NULL, /* base_init */
33 NULL, /* base_finalize */
34 NULL, /* class init */
35 NULL, /* class_finalize */
36 NULL, /* class_data */
37 sizeof(GameRules),
38 0,
39 NULL,
40 NULL
41 };
42 gp_type =
43 g_type_register_static(GTK_TYPE_GRID,
44 "GameRules", &gp_info, 0);
45 }
46 return gp_type;
47 }
48
add_row(GameRules * gr,const gchar * name,const gchar * tooltip,guint row,GtkCheckButton ** check)49 static void add_row(GameRules * gr, const gchar * name,
50 const gchar * tooltip, guint row,
51 GtkCheckButton ** check)
52 {
53 GtkWidget *check_btn;
54
55 check_btn = gtk_check_button_new_with_label(name);
56 gtk_widget_show(check_btn);
57 gtk_grid_attach(GTK_GRID(gr), check_btn, 0, row, 2, 1);
58 *check = GTK_CHECK_BUTTON(check_btn);
59
60 gtk_widget_set_tooltip_text(check_btn, tooltip);
61 }
62
63 /* Build the composite widget */
game_rules_init(GameRules * gr,gboolean show_all_rules)64 static void game_rules_init(GameRules * gr, gboolean show_all_rules)
65 {
66 GtkWidget *label;
67 GtkWidget *vbox_sevens;
68 GtkWidget *hbox;
69 GtkWidget *widget;
70 gint idx;
71 guint row;
72
73 gtk_grid_set_row_spacing(GTK_GRID(gr), 3);
74 gtk_grid_set_column_spacing(GTK_GRID(gr), 5);
75
76 row = 0;
77
78 /* Label */
79 label = gtk_label_new(_("Sevens rule"));
80 gtk_widget_show(label);
81 gtk_grid_attach(GTK_GRID(gr), label, 0, row, 1, 1);
82 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
83 gtk_label_set_yalign(GTK_LABEL(label), 0.0);
84
85 gr->radio_sevens[0] = gtk_radio_button_new_with_label(NULL,
86 /* Sevens rule: normal */
87 _("Normal"));
88 gr->radio_sevens[1] =
89 gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON
90 (gr->radio_sevens
91 [0]),
92 /* Sevens rule: reroll on 1st 2 turns */
93 _(""
94 "Reroll on 1st 2 turns"));
95 gr->radio_sevens[2] =
96 gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON
97 (gr->radio_sevens
98 [0]),
99 /* Sevens rule: reroll all 7s */
100 _(""
101 "Reroll all 7s"));
102
103 vbox_sevens = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
104 gtk_box_set_homogeneous(GTK_BOX(vbox_sevens), TRUE);
105 gtk_widget_show(vbox_sevens);
106 gtk_widget_set_tooltip_text(gr->radio_sevens[0],
107 /* Tooltip for sevens rule normal */
108 _(""
109 "All sevens move the robber or pirate"));
110 gtk_widget_set_tooltip_text(gr->radio_sevens[1],
111 /* Tooltip for sevens rule reroll on 1st 2 turns */
112 _(""
113 "In the first two turns all sevens are rerolled"));
114 gtk_widget_set_tooltip_text(gr->radio_sevens[2],
115 /* Tooltip for sevens rule reroll all */
116 _("All sevens are rerolled"));
117
118 for (idx = 0; idx < 3; ++idx) {
119 gtk_widget_show(gr->radio_sevens[idx]);
120 gtk_box_pack_start(GTK_BOX(vbox_sevens),
121 gr->radio_sevens[idx], TRUE, TRUE, 0);
122 }
123 gtk_grid_attach(GTK_GRID(gr), vbox_sevens, 1, row, 1, 1);
124 gtk_widget_set_hexpand(vbox_sevens, TRUE);
125
126 row++;
127 add_row(gr, _("Randomize terrain"), _("Randomize the terrain"),
128 row++, &gr->random_terrain);
129 if (show_all_rules) {
130 add_row(gr, _("Use pirate"),
131 _("Use the pirate to block ships"), row++,
132 &gr->use_pirate);
133 add_row(gr, _("Strict trade"),
134 _("Allow trade only before building or buying"),
135 row++, &gr->strict_trade);
136 add_row(gr, _("Domestic trade"),
137 _("Allow trade between players"), row++,
138 &gr->domestic_trade);
139 add_row(gr, _("Victory at end of turn"),
140 _("Check for victory only at end of turn"), row++,
141 &gr->check_victory_at_end_of_turn);
142
143 add_row(gr, _("Use dice deck"),
144 _
145 ("Use a deck of 36 dice cards instead of real dice"),
146 row++, &gr->use_dice_deck);
147 g_signal_connect(G_OBJECT(gr->use_dice_deck), "toggled",
148 G_CALLBACK(dice_deck_toggled_callback),
149 gr);
150
151
152 /* Label */
153 label = gtk_label_new(_("Number of dice decks"));
154 gtk_widget_show(label);
155 gtk_grid_attach(GTK_GRID(gr), label, 0, row, 1, 1);
156 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
157 gr->num_dice_decks =
158 GTK_SPIN_BUTTON(gtk_spin_button_new_with_range
159 (1, 5, 1));
160 gtk_entry_set_alignment(GTK_ENTRY(gr->num_dice_decks),
161 1.0);
162 gtk_widget_show(GTK_WIDGET(gr->num_dice_decks));
163 gtk_widget_set_sensitive(GTK_WIDGET(gr->num_dice_decks),
164 gtk_toggle_button_get_active
165 (GTK_TOGGLE_BUTTON
166 (gr->use_dice_deck)));
167 gtk_widget_set_tooltip_text(GTK_WIDGET(gr->num_dice_decks),
168 _
169 ("The number of dice decks (of 36 cards each)"));
170 gtk_grid_attach(GTK_GRID(gr),
171 GTK_WIDGET(gr->num_dice_decks), 1, row, 1,
172 1);
173
174 row++;
175 /* Label */
176 label = gtk_label_new(_("Number of removed dice cards"));
177 gtk_widget_show(label);
178 gtk_grid_attach(GTK_GRID(gr), label, 0, row, 1, 1);
179 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
180 gr->num_removed_dice_cards =
181 GTK_SPIN_BUTTON(gtk_spin_button_new_with_range
182 (0, 30, 1));
183 gtk_entry_set_alignment(GTK_ENTRY
184 (gr->num_removed_dice_cards), 1.0);
185 gtk_widget_show(GTK_WIDGET(gr->num_removed_dice_cards));
186 gtk_widget_set_sensitive(GTK_WIDGET
187 (gr->num_removed_dice_cards),
188 gtk_toggle_button_get_active
189 (GTK_TOGGLE_BUTTON
190 (gr->use_dice_deck)));
191 gtk_widget_set_tooltip_text(GTK_WIDGET
192 (gr->num_removed_dice_cards),
193 _
194 ("The number of dice cards that are removed after shuffling the deck"));
195 gtk_grid_attach(GTK_GRID(gr),
196 GTK_WIDGET(gr->num_removed_dice_cards), 1,
197 row, 1, 1);
198
199 row++;
200 /* Label */
201 label = gtk_label_new(_("Island discovery bonuses"));
202 gtk_widget_show(label);
203 gtk_grid_attach(GTK_GRID(gr), label, 0, row, 1, 1);
204 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
205
206 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
207
208 gr->island_bonus = GTK_ENTRY(gtk_entry_new());
209 gtk_widget_show(GTK_WIDGET(gr->island_bonus));
210 gtk_widget_set_tooltip_text(GTK_WIDGET(gr->island_bonus),
211 /* Tooltip for island bonus */
212 _(""
213 "A comma separated list of "
214 "bonus points for discovering "
215 "islands"));
216 gtk_box_pack_start(GTK_BOX(hbox),
217 GTK_WIDGET(gr->island_bonus), TRUE,
218 TRUE, 0);
219
220 widget = gtk_button_new();
221 gtk_button_set_image(GTK_BUTTON(widget),
222 gtk_image_new_from_icon_name
223 ("pioneers-checkmark",
224 GTK_ICON_SIZE_BUTTON));
225 g_signal_connect(G_OBJECT(widget), "clicked",
226 G_CALLBACK(verify_island_discovery_bonus),
227 (gpointer) gr);
228 gtk_widget_set_tooltip_text(widget,
229 /* Tooltip for the check button */
230 _("Check and correct island "
231 "discovery bonuses"));
232 gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
233
234 gtk_grid_attach(GTK_GRID(gr), GTK_WIDGET(hbox), 1, row, 1,
235 1);
236 row++;
237 } else {
238 gr->use_pirate = NULL;
239 gr->strict_trade = NULL;
240 gr->domestic_trade = NULL;
241 gr->check_victory_at_end_of_turn = NULL;
242 gr->island_bonus = NULL;
243 }
244 }
245
246 /* Create a new instance of the widget */
game_rules_new(void)247 GtkWidget *game_rules_new(void)
248 {
249 GameRules *widget =
250 GAMERULES(g_object_new(game_rules_get_type(), NULL));
251 game_rules_init(widget, TRUE);
252 return GTK_WIDGET(widget);
253 }
254
255
256 /* Create a new instance with only the changes that can be applied by the metaserver */
game_rules_new_metaserver(void)257 GtkWidget *game_rules_new_metaserver(void)
258 {
259 GameRules *widget =
260 GAMERULES(g_object_new(game_rules_get_type(), NULL));
261 game_rules_init(widget, FALSE);
262 return GTK_WIDGET(widget);
263 }
264
game_rules_set_random_terrain(GameRules * gr,gboolean val)265 void game_rules_set_random_terrain(GameRules * gr, gboolean val)
266 {
267 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gr->random_terrain),
268 val);
269 }
270
game_rules_get_random_terrain(GameRules * gr)271 gboolean game_rules_get_random_terrain(GameRules * gr)
272 {
273 return
274 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
275 (gr->random_terrain));
276 }
277
278 /* Set the sevens rule
279 * 0 = Normal
280 * 1 = Reroll first two turns
281 * 2 = Reroll all
282 */
game_rules_set_sevens_rule(GameRules * gr,guint sevens_rule)283 void game_rules_set_sevens_rule(GameRules * gr, guint sevens_rule)
284 {
285 g_return_if_fail(sevens_rule < G_N_ELEMENTS(gr->radio_sevens));
286
287 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
288 (gr->radio_sevens[sevens_rule]),
289 TRUE);
290
291 }
292
293 /* Get the sevens rule */
game_rules_get_sevens_rule(GameRules * gr)294 guint game_rules_get_sevens_rule(GameRules * gr)
295 {
296 guint idx;
297
298 for (idx = 0; idx < G_N_ELEMENTS(gr->radio_sevens); idx++)
299 if (gtk_toggle_button_get_active
300 (GTK_TOGGLE_BUTTON(gr->radio_sevens[idx])))
301 return idx;
302 return 0;
303 }
304
game_rules_set_use_dice_deck(GameRules * gr,gboolean val)305 void game_rules_set_use_dice_deck(GameRules * gr, gboolean val)
306 {
307 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gr->use_dice_deck),
308 val);
309 }
310
game_rules_get_use_dice_deck(GameRules * gr)311 gboolean game_rules_get_use_dice_deck(GameRules * gr)
312 {
313 return
314 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
315 (gr->use_dice_deck));
316 }
317
game_rules_set_num_dice_decks(GameRules * gr,guint val)318 void game_rules_set_num_dice_decks(GameRules * gr, guint val)
319 {
320 gtk_spin_button_set_value(gr->num_dice_decks, val);
321 }
322
game_rules_get_num_dice_decks(GameRules * gr)323 guint game_rules_get_num_dice_decks(GameRules * gr)
324 {
325 return gtk_spin_button_get_value_as_int(gr->num_dice_decks);
326 }
327
game_rules_set_num_removed_dice_cards(GameRules * gr,guint val)328 void game_rules_set_num_removed_dice_cards(GameRules * gr, guint val)
329 {
330 gtk_spin_button_set_value(gr->num_removed_dice_cards, val);
331 }
332
game_rules_get_num_removed_dice_cards(GameRules * gr)333 guint game_rules_get_num_removed_dice_cards(GameRules * gr)
334 {
335 return
336 gtk_spin_button_get_value_as_int(gr->num_removed_dice_cards);
337 }
338
game_rules_set_use_pirate(GameRules * gr,gboolean val,gint num_ships)339 void game_rules_set_use_pirate(GameRules * gr, gboolean val,
340 gint num_ships)
341 {
342 if (num_ships == 0) {
343 gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON
344 (gr->use_pirate), TRUE);
345 gtk_widget_set_sensitive(GTK_WIDGET(gr->use_pirate),
346 FALSE);
347 } else {
348 gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON
349 (gr->use_pirate),
350 FALSE);
351 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
352 (gr->use_pirate), val);
353 gtk_widget_set_sensitive(GTK_WIDGET(gr->use_pirate), TRUE);
354 }
355 }
356
game_rules_get_use_pirate(GameRules * gr)357 gboolean game_rules_get_use_pirate(GameRules * gr)
358 {
359 return
360 gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON
361 (gr->use_pirate)) ? FALSE :
362 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
363 (gr->use_pirate));
364 }
365
game_rules_set_strict_trade(GameRules * gr,gboolean val)366 void game_rules_set_strict_trade(GameRules * gr, gboolean val)
367 {
368 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gr->strict_trade),
369 val);
370 }
371
game_rules_get_strict_trade(GameRules * gr)372 gboolean game_rules_get_strict_trade(GameRules * gr)
373 {
374 return
375 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
376 (gr->strict_trade));
377 }
378
game_rules_set_domestic_trade(GameRules * gr,gboolean val)379 void game_rules_set_domestic_trade(GameRules * gr, gboolean val)
380 {
381 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gr->domestic_trade),
382 val);
383 }
384
game_rules_get_domestic_trade(GameRules * gr)385 gboolean game_rules_get_domestic_trade(GameRules * gr)
386 {
387 return
388 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
389 (gr->domestic_trade));
390 }
391
game_rules_set_victory_at_end_of_turn(GameRules * gr,gboolean val)392 void game_rules_set_victory_at_end_of_turn(GameRules * gr, gboolean val)
393 {
394 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
395 (gr->check_victory_at_end_of_turn),
396 val);
397 }
398
game_rules_get_victory_at_end_of_turn(GameRules * gr)399 gboolean game_rules_get_victory_at_end_of_turn(GameRules * gr)
400 {
401 return
402 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
403 (gr->
404 check_victory_at_end_of_turn));
405 }
406
game_rules_set_island_discovery_bonus(GameRules * gr,GArray * val)407 void game_rules_set_island_discovery_bonus(GameRules * gr, GArray * val)
408 {
409 gchar *text;
410
411 text = format_int_list(NULL, val);
412 if (text != NULL) {
413 gtk_entry_set_text(gr->island_bonus, text);
414 } else {
415 gtk_entry_set_text(gr->island_bonus, "");
416 }
417 g_free(text);
418 }
419
game_rules_get_island_discovery_bonus(GameRules * gr)420 GArray *game_rules_get_island_discovery_bonus(GameRules * gr)
421 {
422 return build_int_list(gtk_entry_get_text(gr->island_bonus));
423 }
424
verify_island_discovery_bonus(G_GNUC_UNUSED GtkButton * button,gpointer user_data)425 static void verify_island_discovery_bonus(G_GNUC_UNUSED GtkButton * button,
426 gpointer user_data)
427 {
428 GameRules *gr = GAMERULES(user_data);
429 GArray *bonuses;
430
431 bonuses = game_rules_get_island_discovery_bonus(gr);
432 game_rules_set_island_discovery_bonus(gr, bonuses);
433 if (bonuses != NULL)
434 g_array_free(bonuses, TRUE);
435 }
436