1
/**********************************************************************
2
Freeciv - Copyright (C) 2005 - The Freeciv Poject
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; either version 2, or (at your option)
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
12
***********************************************************************/
34
#include "client_main.h"
38
#include "mapctrl_common.h"
39
#include "mapview_common.h"
42
#include "editgui_g.h"
43
#include "mapview_g.h"
46
enum selection_modes {
47
SELECTION_MODE_NEW = 0,
52
enum editor_tool_flags {
57
ETF_HAS_APPLIED_PLAYER = 1<<3,
58
ETF_HAS_VALUE_ERASE = 1<<4
63
struct tile_list *vtiles;
64
const struct tile *origin;
69
enum editor_tool_mode mode;
72
int applied_player_no;
79
enum editor_tool_type tool;
80
struct editor_tool tools[NUM_EDITOR_TOOL_TYPES];
82
const struct tile *current_tile;
93
enum selection_modes selection_mode;
95
struct hash_table *selected_tile_table;
96
struct edit_buffer *copybuf;
99
static struct editor_state *editor;
101
/****************************************************************************
102
Initialize editor tool data.
103
****************************************************************************/
104
static void tool_init(enum editor_tool_type ett, const char *name,
105
int flags, const char *tooltip)
107
struct editor_tool *tool;
109
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
113
tool = editor->tools + ett;
115
if (ett == ETT_COPYPASTE) {
116
tool->mode = ETM_COPY;
118
tool->mode = ETM_PAINT;
122
tool->tooltip = tooltip;
125
tool->applied_player_no = 0;
128
/****************************************************************************
129
Initialize the client's editor state information to some suitable default
130
values. This only needs to be done once at client start.
131
****************************************************************************/
132
void editor_init(void)
134
if (editor != NULL) {
138
editor = fc_calloc(1, sizeof(struct editor_state));
140
tool_init(ETT_TERRAIN, _("Terrain"),
141
ETF_HAS_VALUE | ETF_HAS_SIZE,
142
_("Change tile terrain.\nShortcut: t\n"
143
"Select terrain type: shift+t or right-click here."));
144
tool_init(ETT_TERRAIN_RESOURCE, _("Terrain Resource"),
145
ETF_HAS_VALUE | ETF_HAS_SIZE,
146
_("Change tile terrain resources.\nShortcut: r\n"
147
"Select resource type: shift+r or right-click here."));
148
tool_init(ETT_TERRAIN_SPECIAL, _("Terrain Special"), ETF_HAS_VALUE
149
| ETF_HAS_SIZE | ETF_HAS_VALUE_ERASE,
150
_("Modify tile specials.\nShortcut: s\n"
151
"Select special type: shift+s or right-click here."));
152
tool_init(ETT_MILITARY_BASE, _("Military Base"), ETF_HAS_VALUE
153
| ETF_HAS_SIZE | ETF_HAS_VALUE_ERASE,
154
_("Create a military base.\nShortcut: m\n"
155
"Select base type: shift+m or right-click here."));
156
tool_init(ETT_UNIT, _("Unit"), ETF_HAS_VALUE | ETF_HAS_COUNT
157
| ETF_HAS_APPLIED_PLAYER | ETF_HAS_VALUE_ERASE,
158
_("Create unit.\nShortcut: u\nSelect unit "
159
"type: shift+u or right-click here."));
160
tool_init(ETT_CITY, _("City"), ETF_HAS_SIZE | ETF_HAS_APPLIED_PLAYER,
161
_("Create city.\nShortcut: c"));
162
tool_init(ETT_VISION, _("Vision"), ETF_HAS_SIZE,
163
_("Modify player's tile knowledge.\nShortcut: v"));
164
tool_init(ETT_STARTPOS, _("Start Position"), ETF_HAS_APPLIED_PLAYER,
165
_("Place a player start position.\nShortcut: p"));
167
tool_init(ETT_COPYPASTE, _("Copy/Paste"), ETF_HAS_SIZE,
168
_("Copy and paste tiles.\n"
169
"Shortcut for copy mode: shift-c\n"
170
"Shoftcut for paste mode: shift-v"));
171
editor->copybuf = edit_buffer_new(EBT_ALL);
173
editor->selected_tile_table = hash_new(hash_fval_keyval,
175
hash_set_no_shrink(editor->selected_tile_table, TRUE);
178
/****************************************************************************
179
Set the current tool to be used by the editor.
180
****************************************************************************/
181
void editor_set_tool(enum editor_tool_type ett)
183
if (editor == NULL) {
187
if (!(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
194
/****************************************************************************
195
Get the current tool used by the editor.
196
****************************************************************************/
197
enum editor_tool_type editor_get_tool(void)
199
if (editor == NULL) {
200
return NUM_EDITOR_TOOL_TYPES;
206
/****************************************************************************
207
Set the mode for the editor tool.
208
****************************************************************************/
209
void editor_tool_set_mode(enum editor_tool_type ett,
210
enum editor_tool_mode etm)
212
if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
213
|| !(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)
214
|| !editor_tool_has_mode(ett, etm)) {
218
editor->tools[ett].mode = etm;
221
/****************************************************************************
222
Return TRUE if the given tool supports the given mode.
223
****************************************************************************/
224
bool editor_tool_has_mode(enum editor_tool_type ett,
225
enum editor_tool_mode etm)
227
if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
228
|| !(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)) {
232
if (etm == ETM_COPY || etm == ETM_PASTE) {
233
return ett == ETT_COPYPASTE;
236
if (ett == ETT_COPYPASTE) {
237
return etm == ETM_COPY || etm == ETM_PASTE;
243
/****************************************************************************
244
Get the mode for the tool.
245
****************************************************************************/
246
enum editor_tool_mode editor_tool_get_mode(enum editor_tool_type ett)
248
if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
249
return NUM_EDITOR_TOOL_MODES;
251
return editor->tools[ett].mode;
254
/****************************************************************************
255
Returns TRUE if the *client* is in edit mode.
256
****************************************************************************/
257
bool editor_is_active(void)
259
return can_conn_edit(&client.conn);
262
/****************************************************************************
263
Returns TRUE if the given tool should be made availble to the user via
264
the editor GUI. For example, this will return FALSE for ETT_MILITARY_BASE
265
if there are no bases defined in the ruleset.
267
NB: This depends on the ruleset information received from the server, so
268
it will return FALSE if the client does not have it yet.
269
****************************************************************************/
270
bool editor_tool_is_usable(enum editor_tool_type ett)
272
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
277
case ETT_MILITARY_BASE:
278
return base_count() > 0;
280
case ETT_TERRAIN_RESOURCE:
281
return resource_count() > 0;
284
return utype_count() > 0;
292
/****************************************************************************
293
Returns TRUE if the given tool type has sub-values (e.g. the terrain
294
tool has values corresponding to the terrain types).
295
****************************************************************************/
296
bool editor_tool_has_value(enum editor_tool_type ett)
298
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
301
return editor->tools[ett].flags & ETF_HAS_VALUE;
304
/****************************************************************************
305
Set the value ID for the given tool. How the value is interpreted depends
307
****************************************************************************/
308
void editor_tool_set_value(enum editor_tool_type ett, int value)
310
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
311
|| !editor_tool_has_value(ett)) {
314
editor->tools[ett].value = value;
317
/****************************************************************************
318
Get the current tool sub-value.
319
****************************************************************************/
320
int editor_tool_get_value(enum editor_tool_type ett)
322
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
323
|| !editor_tool_has_value(ett)) {
327
return editor->tools[ett].value;
330
/****************************************************************************
331
Record the start of the selection rectangle.
332
****************************************************************************/
333
static void editor_start_selection_rectangle(int canvas_x, int canvas_y)
339
if (editor->selection_mode == SELECTION_MODE_NEW
340
&& editor_selection_count() > 0) {
341
editor_selection_clear();
342
update_map_canvas_visible();
345
editor->selrect_start_x = canvas_x;
346
editor->selrect_start_y = canvas_y;
347
editor->selrect_width = 0;
348
editor->selrect_height = 0;
349
editor->selrect_active = TRUE;
352
/****************************************************************************
353
Temporary convenience function to work-around the fact that certain
354
special values (S_RESOURCE_VALID) do not in fact
355
correspond to drawable special types.
356
****************************************************************************/
357
static inline bool tile_really_has_any_specials(const struct tile *ptile)
365
specials = tile_specials(ptile);
367
BV_CLR(specials, S_RESOURCE_VALID);
369
return BV_ISSET_ANY(specials);
372
/****************************************************************************
373
Set the editor's current applied player number according to what exists
375
****************************************************************************/
376
static void editor_grab_applied_player(const struct tile *ptile)
380
if (!editor || !ptile) {
384
if (client_has_player()
385
&& tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
389
if (tile_city(ptile) != NULL) {
390
apno = player_number(city_owner(tile_city(ptile)));
391
} else if (unit_list_size(ptile->units) > 0) {
392
struct unit *punit = unit_list_get(ptile->units, 0);
393
apno = player_number(unit_owner(punit));
394
} else if (tile_owner(ptile) != NULL) {
395
apno = player_number(tile_owner(ptile));
398
if (valid_player_by_number(apno) != NULL) {
399
editor_tool_set_applied_player(editor_get_tool(), apno);
404
/****************************************************************************
405
Set the editor's current tool according to what exists at the given tile.
406
****************************************************************************/
407
static void editor_grab_tool(const struct tile *ptile)
409
int ett = -1, value = 0;
410
struct base_type *first_base = NULL;
420
base_type_iterate(pbase) {
421
if (tile_has_base(ptile, pbase)) {
425
} base_type_iterate_end;
427
if (client_has_player()
428
&& tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
431
} else if (tile_city(ptile)) {
434
} else if (unit_list_size(ptile->units) > 0) {
435
int max_score = 0, score;
436
struct unit *grabbed_punit = NULL;
437
unit_list_iterate(ptile->units, punit) {
439
if (uclass_has_flag(unit_class(punit), UCF_UNREACHABLE)) {
441
} else if (is_ground_unit(punit)) {
443
} else if (is_sailing_unit(punit)) {
448
if (punit->transported_by > 0) {
452
if (score > max_score) {
454
grabbed_punit = punit;
456
} unit_list_iterate_end;
460
value = utype_number(unit_type(grabbed_punit));
462
} else if (first_base != NULL) {
463
ett = ETT_MILITARY_BASE;
464
value = base_number(first_base);
466
} else if (tile_really_has_any_specials(ptile)) {
467
int specials_array[S_LAST];
468
int count = 0, i, special = -1;
470
tile_special_type_iterate(s) {
471
specials_array[count++] = s;
472
} tile_special_type_iterate_end;
474
/* Grab specials in reverse order of enum tile_special_type. */
476
for (i = count - 1; i >= 0; i--) {
477
if (tile_has_special(ptile, specials_array[i])) {
478
special = specials_array[i];
484
ett = ETT_TERRAIN_SPECIAL;
487
} else if (tile_resource(ptile) != NULL) {
488
ett = ETT_TERRAIN_RESOURCE;
489
value = resource_number(tile_resource(ptile));
491
} else if (tile_terrain(ptile) != NULL) {
493
value = terrain_number(tile_terrain(ptile));
500
editor_set_tool(ett);
501
if (editor_tool_has_value(ett)) {
502
editor_tool_set_value(ett, value);
507
/****************************************************************************
508
Returns TRUE if the given tile has some objects with editable properties.
509
****************************************************************************/
510
static inline bool can_edit_tile_properties(struct tile *ptile)
512
return ptile != NULL;
515
/****************************************************************************
516
Handle a request to edit the properties for the given tile. If the tile
517
is part of a selection, then all selected tiles are passed to the
519
****************************************************************************/
520
static void popup_properties(struct tile *ptile)
522
struct tile_list *tiles;
528
tiles = tile_list_new();
530
if (editor_tile_is_selected(ptile)) {
531
hash_keys_iterate(editor->selected_tile_table, sel_tile) {
532
if (can_edit_tile_properties(sel_tile)) {
533
tile_list_append(tiles, sel_tile);
535
} hash_keys_iterate_end;
537
if (can_edit_tile_properties(ptile)) {
538
tile_list_append(tiles, ptile);
542
editgui_popup_properties(tiles, NUM_OBJTYPES);
544
tile_list_free(tiles);
547
/****************************************************************************
548
Handle a user's mouse button press at the given point on the map canvas.
549
****************************************************************************/
550
void editor_mouse_button_press(int canvas_x, int canvas_y,
551
int button, int modifiers)
555
if (editor == NULL) {
559
ptile = canvas_pos_to_tile(canvas_x, canvas_y);
566
case MOUSE_BUTTON_LEFT:
567
if (modifiers == EKM_SHIFT) {
568
editor_grab_tool(ptile);
569
} else if (modifiers == EKM_CTRL) {
570
editor_grab_applied_player(ptile);
571
} else if (modifiers == EKM_NONE) {
572
editor->tool_active = TRUE;
573
editor_apply_tool(ptile, FALSE);
574
editor_notify_edit_finished();
575
editor_set_current_tile(ptile);
579
case MOUSE_BUTTON_RIGHT:
580
if (modifiers == (EKM_ALT | EKM_CTRL)) {
581
popup_properties(ptile);
585
if (modifiers == EKM_SHIFT) {
586
editor->selection_mode = SELECTION_MODE_ADD;
587
} else if (modifiers == EKM_ALT) {
588
editor->selection_mode = SELECTION_MODE_REMOVE;
589
} else if (modifiers == EKM_NONE) {
590
editor->selection_mode = SELECTION_MODE_NEW;
594
editor_start_selection_rectangle(canvas_x, canvas_y);
597
case MOUSE_BUTTON_MIDDLE:
598
if (modifiers == EKM_NONE) {
599
popup_properties(ptile);
608
/****************************************************************************
609
Record and handle the end of the selection rectangle.
610
****************************************************************************/
611
static void editor_end_selection_rectangle(int canvas_x, int canvas_y)
619
editor->selrect_active = FALSE;
621
if (editor->selrect_width <= 0 || editor->selrect_height <= 0) {
624
ptile = canvas_pos_to_tile(canvas_x, canvas_y);
625
if (ptile && editor->selection_mode == SELECTION_MODE_ADD) {
626
editor_selection_add(ptile);
627
} else if (ptile && editor->selection_mode == SELECTION_MODE_REMOVE) {
628
editor_selection_remove(ptile);
630
recenter_button_pressed(canvas_x, canvas_y);
635
refresh_tile_mapcanvas(ptile, TRUE, TRUE);
641
gui_rect_iterate(mapview.gui_x0 + editor->selrect_x,
642
mapview.gui_y0 + editor->selrect_y,
643
editor->selrect_width, editor->selrect_height,
644
ptile, pedge, pcorner, gui_x, gui_y) {
648
if (editor->selection_mode == SELECTION_MODE_NEW
649
|| editor->selection_mode == SELECTION_MODE_ADD) {
650
editor_selection_add(ptile);
651
} else if (editor->selection_mode == SELECTION_MODE_REMOVE) {
652
editor_selection_remove(ptile);
654
} gui_rect_iterate_end;
656
w = tileset_tile_width(tileset);
657
h = tileset_tile_height(tileset);
659
update_map_canvas(editor->selrect_x - w,
660
editor->selrect_y - h,
661
editor->selrect_width + 2 * w,
662
editor->selrect_height + 2 * h);
666
/****************************************************************************
667
Draws the editor selection rectangle using draw_selection_rectangle().
668
****************************************************************************/
669
static void editor_draw_selrect(void)
675
if (editor->selrect_active && editor->selrect_width > 0
676
&& editor->selrect_height > 0) {
677
draw_selection_rectangle(editor->selrect_x,
679
editor->selrect_width,
680
editor->selrect_height);
684
/****************************************************************************
685
Handle the release of a mouse button click.
686
****************************************************************************/
687
void editor_mouse_button_release(int canvas_x, int canvas_y,
688
int button, int modifiers)
692
case MOUSE_BUTTON_LEFT:
693
editor_set_current_tile(NULL);
694
editor->tool_active = FALSE;
697
case MOUSE_BUTTON_RIGHT:
698
if (editor->selrect_active) {
699
editor_end_selection_rectangle(canvas_x, canvas_y);
703
case MOUSE_BUTTON_MIDDLE:
711
/****************************************************************************
712
Handle a change in the size of the selection rectangle. The given point
713
is the new extremity of the rectangle.
714
****************************************************************************/
715
static void editor_resize_selection_rectangle(int canvas_x, int canvas_y)
719
if (editor->selrect_start_x <= canvas_x) {
720
x1 = editor->selrect_start_x;
724
x2 = editor->selrect_start_x;
727
if (editor->selrect_start_y <= canvas_y) {
728
y1 = editor->selrect_start_y;
732
y2 = editor->selrect_start_y;
735
/* Erase the previously drawn rectangle. */
736
editor_draw_selrect();
738
if (x1 == x2 || y1 == y2) {
739
editor->selrect_width = 0;
740
editor->selrect_height = 0;
744
editor->selrect_x = x1;
745
editor->selrect_y = y1;
746
editor->selrect_width = x2 - x1;
747
editor->selrect_height = y2 - y1;
749
editor_draw_selrect();
752
/****************************************************************************
753
Handle the mouse moving over the map canvas.
754
****************************************************************************/
755
void editor_mouse_move(int canvas_x, int canvas_y, int modifiers)
757
const struct tile *ptile, *old;
763
old = editor_get_current_tile();
764
ptile = canvas_pos_to_tile(canvas_x, canvas_y);
770
if (editor->tool_active && old != NULL && old != ptile) {
771
editor_apply_tool(ptile, FALSE);
772
editor_notify_edit_finished();
773
editor_set_current_tile(ptile);
776
if (editor->selrect_active) {
777
editor_resize_selection_rectangle(canvas_x, canvas_y);
781
/****************************************************************************
782
Notify the server that a batch of edits has completed. This is used as
783
a hint for the server to now do any checks it has saved while the batch
785
****************************************************************************/
786
void editor_notify_edit_finished(void)
788
send_packet_edit_check_tiles(&client.conn);
791
/****************************************************************************
792
Apply the current editor tool to the given tile. This function is
793
suitable to called over multiple tiles at once. Once the batch of
794
operations is finished you should call editor_notify_edit_finished.
795
The 'part_of_selection' parameter should be TRUE if the tool is
796
being applied to a tile from a selection.
797
****************************************************************************/
798
void editor_apply_tool(const struct tile *ptile,
799
bool part_of_selection)
801
enum editor_tool_type ett;
802
enum editor_tool_mode etm;
803
int value, size, count, apno, x, y, id;
805
struct connection *my_conn = &client.conn;
807
if (editor == NULL || ptile == NULL) {
811
ett = editor_get_tool();
812
etm = editor_tool_get_mode(ett);
813
size = editor_tool_get_size(ett);
814
count = editor_tool_get_count(ett);
815
value = editor_tool_get_value(ett);
816
apno = editor_tool_get_applied_player(ett);
818
if (ett != ETT_VISION && !client_is_global_observer()
819
&& client_has_player()
820
&& tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
824
if (editor_tool_has_applied_player(ett)
825
&& valid_player_by_number(apno) == NULL) {
829
if (ett == ETT_COPYPASTE) {
830
struct edit_buffer *ebuf;
831
ebuf = editor_get_copy_buffer();
832
if (etm == ETM_COPY) {
833
if (part_of_selection) {
834
edit_buffer_copy(ebuf, ptile);
836
edit_buffer_clear(ebuf);
837
edit_buffer_copy_square(ebuf, ptile, size);
840
} else if (etm == ETM_PAINT || etm == ETM_PASTE) {
841
edit_buffer_paste(ebuf, ptile);
846
if (part_of_selection && ett != ETT_CITY) {
850
erase = (etm == ETM_ERASE);
857
dsend_packet_edit_tile_terrain(my_conn, x, y, erase ? 0 : value, size);
860
case ETT_TERRAIN_RESOURCE:
861
dsend_packet_edit_tile_resource(my_conn, x, y, erase ? -1 : value,
865
case ETT_TERRAIN_SPECIAL:
866
dsend_packet_edit_tile_special(my_conn, x, y, value, erase, size);
869
case ETT_MILITARY_BASE:
870
dsend_packet_edit_tile_base(my_conn, x, y, value, erase, size);
875
dsend_packet_edit_unit_remove(my_conn, apno, x, y, value, count);
877
dsend_packet_edit_unit_create(my_conn, apno, x, y, value, count, 0);
883
struct city *pcity = tile_city(ptile);
886
dsend_packet_edit_city_remove(my_conn, id);
889
dsend_packet_edit_city_create(my_conn, apno, x, y, size, 0);
894
if (client_has_player()) {
895
id = client_player_number();
896
dsend_packet_edit_player_vision(my_conn, id, x, y, !erase, size);
901
dsend_packet_edit_startpos(my_conn, x, y,
902
erase ? NATION_NONE :
903
nation_number(player_by_number(apno)->nation));
911
/****************************************************************************
912
Sets the tile currently assumed to be under the user's mouse pointer.
913
****************************************************************************/
914
void editor_set_current_tile(const struct tile *ptile)
916
if (editor == NULL) {
920
editor->current_tile = ptile;
923
/****************************************************************************
924
Get the tile that the user's mouse pointer is currently over.
925
****************************************************************************/
926
const struct tile *editor_get_current_tile(void)
928
if (editor == NULL) {
932
return editor->current_tile;
935
/****************************************************************************
936
Toggle the current tool mode between the given mode and ETM_PAINT (or
937
ETM_COPY for the copy & paste tool).
938
****************************************************************************/
939
void editor_tool_toggle_mode(enum editor_tool_type ett,
940
enum editor_tool_mode etm)
942
if (!editor_tool_has_mode(ett, etm)) {
945
if (editor_tool_get_mode(ett) == etm) {
946
editor_tool_set_mode(ett, ett == ETT_COPYPASTE
947
? ETM_COPY : ETM_PAINT);
949
editor_tool_set_mode(ett, etm);
953
/****************************************************************************
954
Set the editor tool mode to the next available mode.
955
****************************************************************************/
956
void editor_tool_cycle_mode(enum editor_tool_type ett)
961
mode = editor_tool_get_mode(ett);
962
if (!(0 <= mode && mode < NUM_EDITOR_TOOL_MODES)) {
966
for (count = 0; count < NUM_EDITOR_TOOL_MODES; count++) {
967
mode = (mode + 1) % NUM_EDITOR_TOOL_MODES;
968
if (editor_tool_has_mode(ett, mode)) {
975
editor_tool_set_mode(ett, mode);
979
/****************************************************************************
980
Unselect all selected tiles.
981
****************************************************************************/
982
void editor_selection_clear(void)
987
hash_delete_all_entries(editor->selected_tile_table);
990
/****************************************************************************
991
Add the given tile to the current selection.
992
****************************************************************************/
993
void editor_selection_add(const struct tile *ptile)
995
if (!editor || !ptile) {
998
hash_insert(editor->selected_tile_table, ptile, NULL);
1001
/****************************************************************************
1002
Remove the given tile from the current selection.
1003
****************************************************************************/
1004
void editor_selection_remove(const struct tile *ptile)
1006
if (!editor || !ptile) {
1009
hash_delete_entry(editor->selected_tile_table, ptile);
1012
/****************************************************************************
1013
Returns TRUE if the given tile is selected.
1014
****************************************************************************/
1015
bool editor_tile_is_selected(const struct tile *ptile)
1017
if (!editor || !ptile) {
1020
return hash_key_exists(editor->selected_tile_table, ptile);
1023
/****************************************************************************
1024
Apply the current editor tool to all tiles in the current selection.
1025
****************************************************************************/
1026
void editor_apply_tool_to_selection(void)
1028
enum editor_tool_type ett;
1030
if (!editor || editor_selection_count() <= 0) {
1034
ett = editor_get_tool();
1035
if (editor_tool_get_mode(ett) == ETM_COPY) {
1036
struct edit_buffer *ebuf;
1037
ebuf = editor_get_copy_buffer();
1038
edit_buffer_clear(ebuf);
1039
edit_buffer_set_origin(ebuf, editor_get_selection_center());
1042
connection_do_buffer(&client.conn);
1043
hash_keys_iterate(editor->selected_tile_table, ptile) {
1044
editor_apply_tool(ptile, TRUE);
1045
} hash_keys_iterate_end;
1046
editor_notify_edit_finished();
1047
connection_do_unbuffer(&client.conn);
1049
if (editor_tool_get_mode(ett) == ETM_COPY) {
1054
/****************************************************************************
1055
Get the translated name of the given tool type.
1056
****************************************************************************/
1057
const char *editor_tool_get_name(enum editor_tool_type ett)
1059
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1063
return editor->tools[ett].name;
1066
/****************************************************************************
1067
Get the translated name of the given tool value. If no such name exists,
1068
returns an empty string.
1069
****************************************************************************/
1070
const char *editor_tool_get_value_name(enum editor_tool_type emt, int value)
1072
struct terrain *pterrain;
1073
struct resource *presource;
1074
struct unit_type *putype;
1075
struct base_type *pbase;
1083
pterrain = terrain_by_number(value);
1084
return pterrain ? terrain_name_translation(pterrain) : "";
1086
case ETT_TERRAIN_RESOURCE:
1087
presource = resource_by_number(value);
1088
return presource ? resource_name_translation(presource) : "";
1090
case ETT_TERRAIN_SPECIAL:
1091
if (!(0 <= value && value < S_LAST)) {
1094
return special_name_translation(value);
1096
case ETT_MILITARY_BASE:
1097
pbase = base_by_number(value);
1098
return pbase != NULL ? base_name_translation(pbase) : "";
1101
putype = utype_by_number(value);
1102
return putype ? utype_name_translation(putype) : "";
1110
/****************************************************************************
1111
Return TRUE if the given editor tool uses the 'size' parameter.
1112
****************************************************************************/
1113
bool editor_tool_has_size(enum editor_tool_type ett)
1115
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1118
return editor->tools[ett].flags & ETF_HAS_SIZE;
1121
/****************************************************************************
1122
Returns the current size parameter for the given editor tools.
1123
****************************************************************************/
1124
int editor_tool_get_size(enum editor_tool_type ett)
1126
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1129
return editor->tools[ett].size;
1132
/****************************************************************************
1133
Sets the size parameter for the given tool.
1134
****************************************************************************/
1135
void editor_tool_set_size(enum editor_tool_type ett, int size)
1137
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1140
editor->tools[ett].size = MAX(1, size);
1143
/****************************************************************************
1144
Return TRUE if it is meaningful for the given tool to use the 'count'
1146
****************************************************************************/
1147
bool editor_tool_has_count(enum editor_tool_type ett)
1149
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1152
return editor->tools[ett].flags & ETF_HAS_COUNT;
1155
/****************************************************************************
1156
Returns the 'count' parameter for the editor tool.
1157
****************************************************************************/
1158
int editor_tool_get_count(enum editor_tool_type ett)
1160
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1163
return editor->tools[ett].count;
1166
/****************************************************************************
1167
Sets the 'count' parameter of the tool to the given value.
1168
****************************************************************************/
1169
void editor_tool_set_count(enum editor_tool_type ett, int count)
1171
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1174
editor->tools[ett].count = MAX(1, count);
1177
/****************************************************************************
1178
Returns a sprite containing an icon for the given tool type. Returns
1179
NULL if no such sprite exists.
1180
****************************************************************************/
1181
struct sprite *editor_tool_get_sprite(enum editor_tool_type ett)
1183
const struct editor_sprites *sprites;
1185
if (!tileset || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1189
sprites = get_editor_sprites(tileset);
1196
return sprites->copypaste;
1199
return sprites->terrain;
1201
case ETT_TERRAIN_RESOURCE:
1202
return sprites->terrain_resource;
1204
case ETT_TERRAIN_SPECIAL:
1205
return sprites->terrain_special;
1207
case ETT_MILITARY_BASE:
1208
return sprites->military_base;
1211
return sprites->unit;
1214
return sprites->city;
1217
return sprites->vision;
1220
return sprites->startpos;
1229
/****************************************************************************
1230
Returns a translated "tooltip" description for the given tool type.
1231
****************************************************************************/
1232
const char *editor_tool_get_tooltip(enum editor_tool_type ett)
1234
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
1235
|| !editor->tools[ett].tooltip) {
1238
return editor->tools[ett].tooltip;
1241
/****************************************************************************
1242
Returns the current applied player number for the editor tool.
1244
May return a player number for which valid_player_by_number returns NULL.
1245
****************************************************************************/
1246
int editor_tool_get_applied_player(enum editor_tool_type ett)
1248
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1251
return editor->tools[ett].applied_player_no;
1254
/****************************************************************************
1255
Sets the editor tool's applied player number to the given value.
1256
****************************************************************************/
1257
void editor_tool_set_applied_player(enum editor_tool_type ett,
1260
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1263
editor->tools[ett].applied_player_no = player_no;
1266
/****************************************************************************
1267
Returns TRUE if the given tool makes use of the editor's applied player
1269
****************************************************************************/
1270
bool editor_tool_has_applied_player(enum editor_tool_type ett)
1272
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1275
return editor->tools[ett].flags & ETF_HAS_APPLIED_PLAYER;
1278
/****************************************************************************
1279
Returns TRUE if erase mode for the given tool erases by sub-value instead
1280
of any object corresponding to the tool type.
1281
****************************************************************************/
1282
bool editor_tool_has_value_erase(enum editor_tool_type ett)
1284
if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1287
return editor->tools[ett].flags & ETF_HAS_VALUE_ERASE;
1290
/****************************************************************************
1291
Returns the number of currently selected tiles.
1292
****************************************************************************/
1293
int editor_selection_count(void)
1298
return hash_num_entries(editor->selected_tile_table);
1301
/****************************************************************************
1302
Creates a virtual unit (like create_unit_virtual) based on the current
1303
editor state. You should free() the unit when it is no longer needed.
1304
If creation is not possible, then NULL is returned.
1306
The virtual unit has no homecity or tile. It is owned by the player
1307
corresponding to the current 'applied player' parameter and has unit type
1308
given by the sub-value of the unit tool (ETT_UNIT).
1309
****************************************************************************/
1310
struct unit *editor_create_unit_virtual(void)
1313
struct player *pplayer;
1314
struct unit_type *putype;
1317
value = editor_tool_get_value(ETT_UNIT);
1318
putype = utype_by_number(value);
1324
apno = editor_tool_get_applied_player(ETT_UNIT);
1325
pplayer = valid_player_by_number(apno);
1330
vunit = create_unit_virtual(pplayer, NULL, putype, 0);
1335
/****************************************************************************
1336
Create a new edit buffer corresponding to all types set in 'type_flags'.
1337
****************************************************************************/
1338
struct edit_buffer *edit_buffer_new(int type_flags)
1340
struct edit_buffer *ebuf;
1342
if (!(0 <= type_flags && type_flags <= EBT_ALL)) {
1346
ebuf = fc_calloc(1, sizeof(*ebuf));
1347
ebuf->type_flags = type_flags;
1348
ebuf->vtiles = tile_list_new();
1353
/****************************************************************************
1354
Free all memory allocated for the edit buffer.
1355
****************************************************************************/
1356
void edit_buffer_free(struct edit_buffer *ebuf)
1363
tile_list_iterate(ebuf->vtiles, vtile) {
1364
destroy_tile_virtual(vtile);
1365
} tile_list_iterate_end;
1366
tile_list_free(ebuf->vtiles);
1367
ebuf->vtiles = NULL;
1372
/****************************************************************************
1373
Remove all copy data stored in the edit buffer.
1374
****************************************************************************/
1375
void edit_buffer_clear(struct edit_buffer *ebuf)
1377
if (!ebuf || !ebuf->vtiles) {
1381
tile_list_iterate(ebuf->vtiles, vtile) {
1382
destroy_tile_virtual(vtile);
1383
} tile_list_iterate_end;
1384
tile_list_clear(ebuf->vtiles);
1386
edit_buffer_set_origin(ebuf, NULL);
1389
/****************************************************************************
1390
Copy from a square region of half-width 'radius' centered around 'center'
1392
****************************************************************************/
1393
void edit_buffer_copy_square(struct edit_buffer *ebuf,
1394
const struct tile *center,
1397
if (!ebuf || !center || radius < 1) {
1401
edit_buffer_set_origin(ebuf, center);
1402
square_iterate(center, radius - 1, ptile) {
1403
edit_buffer_copy(ebuf, ptile);
1404
} square_iterate_end;
1407
/****************************************************************************
1408
Append a single tile to the copy buffer.
1409
****************************************************************************/
1410
void edit_buffer_copy(struct edit_buffer *ebuf, const struct tile *ptile)
1414
const struct tile *origin;
1416
bool copied = FALSE;
1418
if (!ebuf || !ptile) {
1422
origin = edit_buffer_get_origin(ebuf);
1424
map_distance_vector(&dx, &dy, origin, ptile);
1429
vtile = create_tile_virtual();
1433
edit_buffer_type_iterate(ebuf, type) {
1436
if (tile_terrain(ptile)) {
1437
tile_set_terrain(vtile, tile_terrain(ptile));
1442
if (tile_resource(ptile)) {
1443
tile_set_resource(vtile, tile_resource(ptile));
1448
if (tile_has_any_specials(ptile)) {
1449
tile_set_specials(vtile, tile_specials(ptile));
1454
if (tile_has_any_bases(ptile)) {
1455
tile_set_bases(vtile, tile_bases(ptile));
1460
unit_list_iterate(ptile->units, punit) {
1464
vunit = create_unit_virtual(unit_owner(punit), NULL,
1465
unit_type(punit), punit->veteran);
1466
vunit->homecity = punit->homecity;
1467
vunit->hp = punit->hp;
1468
unit_list_append(vtile->units, vunit);
1470
} unit_list_iterate_end;
1473
if (tile_city(ptile)) {
1474
struct city *pcity, *vcity;
1475
char name[MAX_LEN_NAME];
1477
pcity = tile_city(ptile);
1478
my_snprintf(name, sizeof(name), "Copy of %s",
1480
vcity = create_city_virtual(city_owner(pcity), NULL, name);
1481
vcity->size = pcity->size;
1482
improvement_iterate(pimprove) {
1483
if (!is_improvement(pimprove)
1484
|| !city_has_building(pcity, pimprove)) {
1487
city_add_improvement(vcity, pimprove);
1488
} improvement_iterate_end;
1489
tile_set_worked(vtile, vcity);
1496
} edit_buffer_type_iterate_end;
1499
tile_list_append(ebuf->vtiles, vtile);
1501
destroy_tile_virtual(vtile);
1505
/****************************************************************************
1506
Helper function to fill in an edit packet with the tile's current values.
1507
****************************************************************************/
1508
static void fill_tile_edit_packet(struct packet_edit_tile *packet,
1509
const struct tile *ptile)
1511
const struct resource *presource;
1512
const struct terrain *pterrain;
1513
const struct nation_type *pnation;
1515
if (!packet || !ptile) {
1518
packet->id = tile_index(ptile);
1519
packet->specials = tile_specials(ptile);
1520
packet->bases = tile_bases(ptile);
1522
presource = tile_resource(ptile);
1523
packet->resource = presource ? resource_number(presource) : -1;
1525
pterrain = tile_terrain(ptile);
1526
packet->terrain = pterrain ? terrain_number(pterrain) : -1;
1528
pnation = map_get_startpos(ptile);
1529
packet->startpos_nation = pnation ? nation_number(pnation) : -1;
1532
/****************************************************************************
1533
Helper function for edit_buffer_paste(). Do a single paste of the stuff set
1534
in the buffer on the virtual tile to the destination tile 'ptile_dest'.
1535
****************************************************************************/
1536
static void paste_tile(struct edit_buffer *ebuf,
1537
const struct tile *vtile,
1538
const struct tile *ptile_dest)
1540
struct connection *my_conn = &client.conn;
1541
struct packet_edit_tile tile_packet;
1543
int value, owner, x, y;
1544
bool send_edit_tile = FALSE;
1546
if (!ebuf || !vtile || !ptile_dest) {
1553
fill_tile_edit_packet(&tile_packet, ptile_dest);
1555
edit_buffer_type_iterate(ebuf, type) {
1558
if (!tile_terrain(vtile)) {
1561
value = terrain_number(tile_terrain(vtile));
1562
dsend_packet_edit_tile_terrain(my_conn, x, y, value, 1);
1565
if (!tile_resource(vtile)) {
1568
value = resource_number(tile_resource(vtile));
1569
dsend_packet_edit_tile_resource(my_conn, x, y, value, 1);
1572
tile_packet.specials = tile_specials(vtile);
1573
send_edit_tile = TRUE;
1576
tile_packet.bases = tile_bases(vtile);
1577
send_edit_tile = TRUE;
1580
unit_list_iterate(vtile->units, vunit) {
1581
value = utype_number(unit_type(vunit));
1582
owner = player_number(unit_owner(vunit));
1583
dsend_packet_edit_unit_create(my_conn, owner, x, y, value, 1, 0);
1584
} unit_list_iterate_end;
1587
vcity = tile_city(vtile);
1591
owner = player_number(city_owner(vcity));
1592
value = vcity->size;
1593
dsend_packet_edit_city_create(my_conn, owner, x, y, value, 0);
1598
} edit_buffer_type_iterate_end;
1600
if (send_edit_tile) {
1601
send_packet_edit_tile(my_conn, &tile_packet);
1605
/****************************************************************************
1606
Paste the entire contents of the edit buffer using 'dest' as the origin.
1607
****************************************************************************/
1608
void edit_buffer_paste(struct edit_buffer *ebuf, const struct tile *dest)
1610
struct connection *my_conn = &client.conn;
1611
const struct tile *ptile;
1613
if (!ebuf || !dest) {
1617
connection_do_buffer(my_conn);
1618
tile_list_iterate(ebuf->vtiles, vtile) {
1619
ptile = map_pos_to_tile(dest->x + vtile->x, dest->y + vtile->y);
1623
paste_tile(ebuf, vtile, ptile);
1624
} tile_list_iterate_end;
1625
connection_do_unbuffer(my_conn);
1628
/****************************************************************************
1629
Returns the copy buffer for the given tool.
1630
****************************************************************************/
1631
struct edit_buffer *editor_get_copy_buffer(void)
1636
return editor->copybuf;
1639
/****************************************************************************
1640
Returns the translated string name for the given mode.
1641
****************************************************************************/
1642
const char *editor_tool_get_mode_name(enum editor_tool_type ett,
1643
enum editor_tool_mode etm)
1647
value_erase = editor_tool_has_value_erase(ett);
1655
return _("Erase Value");
1667
freelog(LOG_ERROR, "Unrecognized editor tool mode %d "
1668
"in editor_tool_get_mode_name().", etm);
1675
/****************************************************************************
1676
Returns a translated tooltip string assumed to be used for the toggle
1677
button for this tool mode in the editor gui.
1678
****************************************************************************/
1679
const char *editor_get_mode_tooltip(enum editor_tool_mode etm)
1683
return _("Toggle erase mode.\nShortcut: shift-d");
1686
return _("Toggle copy mode.\nShortcut: shift-c");
1689
return _("Toggle paste mode.\nShortcut: shift-v");
1698
/****************************************************************************
1699
Returns the editor sprite corresponding to the tool mode.
1700
****************************************************************************/
1701
struct sprite *editor_get_mode_sprite(enum editor_tool_mode etm)
1703
const struct editor_sprites *sprites;
1705
sprites = get_editor_sprites(tileset);
1712
return sprites->brush;
1715
return sprites->erase;
1718
return sprites->copy;
1721
return sprites->paste;
1730
/****************************************************************************
1731
Fill the supplied buffer with a translated string describing the edit
1732
buffer's current state. Returns the number of bytes used.
1733
****************************************************************************/
1734
int edit_buffer_get_status_string(const struct edit_buffer *ebuf,
1735
char *buf, int buflen)
1740
if (!buf || buflen < 1) {
1744
ret = mystrlcpy(buf, _("Buffer empty."), buflen);
1745
if (!ebuf || !ebuf->vtiles) {
1749
total = tile_list_size(ebuf->vtiles);
1751
fmt = PL_("%d tile copied.", "%d tiles copied.", total);
1752
ret = my_snprintf(buf, buflen, fmt, total);
1758
/****************************************************************************
1759
Set the "origin" for subsequent copy operations. This controls the x and
1760
y offset of newly created virtual tiles in the buffer.
1761
****************************************************************************/
1762
void edit_buffer_set_origin(struct edit_buffer *ebuf,
1763
const struct tile *ptile)
1768
ebuf->origin = ptile;
1771
/****************************************************************************
1772
Return the previously set origin, or NULL if none.
1773
****************************************************************************/
1774
const struct tile *edit_buffer_get_origin(const struct edit_buffer *ebuf)
1779
return ebuf->origin;
1782
/****************************************************************************
1783
Returns TRUE if the edit buffer was created with the given type flag.
1784
****************************************************************************/
1785
bool edit_buffer_has_type(const struct edit_buffer *ebuf, int type)
1790
return ebuf->type_flags & type;
1793
/****************************************************************************
1794
Returns the "center" tile of a group of selected tiles, or NULL.
1795
The center is calculated as the vector sum divided by the number of tiles,
1796
i.e. the average of the map distance vectors of the selected tiles.
1797
****************************************************************************/
1798
const struct tile *editor_get_selection_center(void)
1801
const struct tile *origin, *center;
1803
int xsum = 0, ysum = 0;
1805
if (!editor || !editor->selected_tile_table) {
1809
count = hash_num_entries(editor->selected_tile_table);
1814
origin = map_pos_to_tile(0, 0);
1815
hash_keys_iterate(editor->selected_tile_table, ptile) {
1816
map_distance_vector(&dx, &dy, origin, ptile);
1819
} hash_keys_iterate_end;
1823
center = map_pos_to_tile(cx, cy);