Fixed 'might be used uninitialized' error from qt-client update_units().
[freeciv.git] / client / editor.c
blobd8703ad09fd80ef9fb4cd70cef2b461d6b46ef63
1 /***********************************************************************
2 Freeciv - Copyright (C) 2005 - The Freeciv Project
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)
6 any later version.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdarg.h>
19 #include <string.h>
21 /* utility */
22 #include "bitvector.h"
23 #include "fcintl.h"
24 #include "log.h"
25 #include "support.h"
27 /* common */
28 #include "game.h"
29 #include "map.h"
30 #include "movement.h"
31 #include "packets.h"
33 /* client */
34 #include "client_main.h"
35 #include "climap.h"
36 #include "control.h"
37 #include "editor.h"
38 #include "mapctrl_common.h"
39 #include "tilespec.h"
40 #include "zoom.h"
42 /* client/include */
43 #include "editgui_g.h"
44 #include "mapview_g.h"
47 enum selection_modes {
48 SELECTION_MODE_NEW = 0,
49 SELECTION_MODE_ADD,
50 SELECTION_MODE_REMOVE
53 enum editor_tool_flags {
54 ETF_NO_FLAGS = 0,
55 ETF_HAS_VALUE = 1<<0,
56 ETF_HAS_SIZE = 1<<1,
57 ETF_HAS_COUNT = 1<<2,
58 ETF_HAS_APPLIED_PLAYER = 1<<3,
59 ETF_HAS_VALUE_ERASE = 1<<4
62 struct edit_buffer {
63 int type_flags;
64 struct tile_list *vtiles;
65 const struct tile *origin;
68 struct editor_tool {
69 int flags;
70 enum editor_tool_mode mode;
71 int size;
72 int count;
73 int applied_player_no;
74 const char *name;
75 int value;
76 const char *tooltip;
79 struct editor_state {
80 enum editor_tool_type tool;
81 struct editor_tool tools[NUM_EDITOR_TOOL_TYPES];
83 const struct tile *current_tile;
84 bool tool_active;
86 bool selrect_active;
87 int selrect_start_x;
88 int selrect_start_y;
89 int selrect_x;
90 int selrect_y;
91 int selrect_width;
92 int selrect_height;
94 enum selection_modes selection_mode;
96 struct tile_hash *selected_tile_table;
97 struct edit_buffer *copybuf;
100 static struct editor_state *editor = NULL;
102 /****************************************************************************
103 Set tool to some value legal under current ruleset.
104 ****************************************************************************/
105 static void tool_set_init_value(enum editor_tool_type ett)
107 struct editor_tool *tool = editor->tools + ett;
109 if (ett == ETT_TERRAIN_SPECIAL
110 || ett == ETT_ROAD
111 || ett == ETT_MILITARY_BASE) {
112 struct extra_type *first = NULL;
114 extra_type_iterate(pextra) {
115 if (ett == ETT_ROAD) {
116 if (is_extra_caused_by(pextra, EC_ROAD)) {
117 first = pextra;
118 break;
120 } else if (ett == ETT_MILITARY_BASE) {
121 if (is_extra_caused_by(pextra, EC_BASE)) {
122 first = pextra;
123 break;
125 } else {
126 /* Considers extras that are neither bases or roads, specials */
127 first = pextra;
128 break;
130 } extra_type_iterate_end;
132 if (first != NULL) {
133 tool->value = extra_index(first);
134 } else {
135 tool->value = 0;
137 } else {
138 tool->value = 0;
142 /****************************************************************************
143 Initialize editor tool data.
144 ****************************************************************************/
145 static void tool_init(enum editor_tool_type ett, const char *name,
146 int flags, const char *tooltip)
148 struct editor_tool *tool;
150 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
151 return;
154 tool = editor->tools + ett;
156 if (ett == ETT_COPYPASTE) {
157 tool->mode = ETM_COPY;
158 } else {
159 tool->mode = ETM_PAINT;
161 tool->name = name;
162 tool->flags = flags;
163 tool->tooltip = tooltip;
164 tool->size = 1;
165 tool->count = 1;
166 tool->applied_player_no = 0;
168 tool_set_init_value(ett);
171 /****************************************************************************
172 Adjust editor for changed ruleset.
173 ****************************************************************************/
174 void editor_ruleset_changed(void)
176 int t;
178 for (t = 0; t < NUM_EDITOR_TOOL_TYPES; t++) {
179 tool_set_init_value(t);
183 /****************************************************************************
184 Initialize the client's editor state information to some suitable default
185 values. This only needs to be done once at client start.
186 ****************************************************************************/
187 void editor_init(void)
189 fc_assert(editor == NULL);
191 editor = fc_calloc(1, sizeof(struct editor_state));
193 tool_init(ETT_TERRAIN, _("Terrain"),
194 ETF_HAS_VALUE | ETF_HAS_SIZE,
195 _("Change tile terrain.\nShortcut: t\n"
196 "Select terrain type: shift+t or right-click here."));
197 tool_init(ETT_TERRAIN_RESOURCE, _("Terrain Resource"),
198 ETF_HAS_VALUE | ETF_HAS_SIZE,
199 _("Change tile terrain resources.\nShortcut: r\n"
200 "Select resource type: shift+r or right-click here."));
201 tool_init(ETT_TERRAIN_SPECIAL, _("Terrain Special"), ETF_HAS_VALUE
202 | ETF_HAS_SIZE | ETF_HAS_VALUE_ERASE,
203 _("Modify tile specials.\nShortcut: s\n"
204 "Select special type: shift+s or right-click here."));
205 tool_init(ETT_ROAD, _("Road"), ETF_HAS_VALUE
206 | ETF_HAS_SIZE | ETF_HAS_VALUE_ERASE,
207 _("Modify roads on tile.\nShortcut: p\n"
208 "Select road type: shift+p or right-click here."));
209 tool_init(ETT_MILITARY_BASE, _("Military Base"), ETF_HAS_VALUE
210 | ETF_HAS_SIZE | ETF_HAS_VALUE_ERASE,
211 _("Create a military base.\nShortcut: m\n"
212 "Select base type: shift+m or right-click here."));
213 tool_init(ETT_UNIT, _("Unit"), ETF_HAS_VALUE | ETF_HAS_COUNT
214 | ETF_HAS_APPLIED_PLAYER | ETF_HAS_VALUE_ERASE,
215 _("Create unit.\nShortcut: u\nSelect unit "
216 "type: shift+u or right-click here."));
217 tool_init(ETT_CITY, _("City"), ETF_HAS_SIZE | ETF_HAS_APPLIED_PLAYER,
218 _("Create city.\nShortcut: c"));
219 tool_init(ETT_VISION, _("Vision"), ETF_HAS_SIZE,
220 _("Modify player's tile knowledge.\nShortcut: v"));
221 tool_init(ETT_STARTPOS, _("Start Position"), ETF_NO_FLAGS,
222 _("Place a start position which allows any nation to "
223 "start at the tile. To allow only certain nations to "
224 "start there, middle click on the start position on "
225 "the map and use the property editor.\nShortcut: b"));
227 tool_init(ETT_COPYPASTE, _("Copy/Paste"), ETF_HAS_SIZE,
228 _("Copy and paste tiles.\n"
229 "Shortcut for copy mode: shift-c\n"
230 "Shoftcut for paste mode: shift-v"));
231 editor->copybuf = edit_buffer_new(EBT_ALL);
233 editor->selected_tile_table = tile_hash_new();
234 tile_hash_set_no_shrink(editor->selected_tile_table, TRUE);
237 /****************************************************************************
238 Clear the editor data which is game dependent.
239 ****************************************************************************/
240 void editor_clear(void)
242 fc_assert_ret(editor != NULL);
244 edit_buffer_clear(editor->copybuf);
245 tile_hash_clear(editor->selected_tile_table);
248 /****************************************************************************
249 Free the client's editor.
250 ****************************************************************************/
251 void editor_free(void)
253 fc_assert_ret(editor != NULL);
255 edit_buffer_free(editor->copybuf);
256 tile_hash_destroy(editor->selected_tile_table);
257 free(editor);
258 editor = NULL;
261 /****************************************************************************
262 Set the current tool to be used by the editor.
263 ****************************************************************************/
264 void editor_set_tool(enum editor_tool_type ett)
266 if (editor == NULL) {
267 return;
270 if (!(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
271 return;
274 editor->tool = ett;
277 /****************************************************************************
278 Get the current tool used by the editor.
279 ****************************************************************************/
280 enum editor_tool_type editor_get_tool(void)
282 if (editor == NULL) {
283 return NUM_EDITOR_TOOL_TYPES;
286 return editor->tool;
289 /****************************************************************************
290 Set the mode for the editor tool.
291 ****************************************************************************/
292 void editor_tool_set_mode(enum editor_tool_type ett,
293 enum editor_tool_mode etm)
295 if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
296 || !(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)
297 || !editor_tool_has_mode(ett, etm)) {
298 return;
301 editor->tools[ett].mode = etm;
304 /****************************************************************************
305 Return TRUE if the given tool supports the given mode.
306 ****************************************************************************/
307 bool editor_tool_has_mode(enum editor_tool_type ett,
308 enum editor_tool_mode etm)
310 if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
311 || !(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)) {
312 return FALSE;
315 if (etm == ETM_COPY || etm == ETM_PASTE) {
316 return ett == ETT_COPYPASTE;
319 if (ett == ETT_COPYPASTE) {
320 return etm == ETM_COPY || etm == ETM_PASTE;
323 return TRUE;
326 /****************************************************************************
327 Get the mode for the tool.
328 ****************************************************************************/
329 enum editor_tool_mode editor_tool_get_mode(enum editor_tool_type ett)
331 if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
332 return NUM_EDITOR_TOOL_MODES;
334 return editor->tools[ett].mode;
337 /****************************************************************************
338 Returns TRUE if the *client* is in edit mode.
339 ****************************************************************************/
340 bool editor_is_active(void)
342 return can_conn_edit(&client.conn);
345 /****************************************************************************
346 Returns TRUE if the given tool should be made available to the user via
347 the editor GUI. For example, this will return FALSE for ETT_MILITARY_BASE
348 if there are no bases defined in the ruleset.
350 NB: This depends on the ruleset information received from the server, so
351 it will return FALSE if the client does not have it yet.
352 ****************************************************************************/
353 bool editor_tool_is_usable(enum editor_tool_type ett)
355 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
356 return FALSE;
359 switch (ett) {
360 case ETT_MILITARY_BASE:
361 return base_count() > 0;
362 case ETT_ROAD:
363 return road_count() > 0;
364 case ETT_TERRAIN_RESOURCE:
365 return resource_count() > 0;
366 case ETT_UNIT:
367 return utype_count() > 0;
368 default:
369 break;
371 return TRUE;
374 /****************************************************************************
375 Returns TRUE if the given tool type has sub-values (e.g. the terrain
376 tool has values corresponding to the terrain types).
377 ****************************************************************************/
378 bool editor_tool_has_value(enum editor_tool_type ett)
380 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
381 return FALSE;
383 return editor->tools[ett].flags & ETF_HAS_VALUE;
386 /****************************************************************************
387 Set the value ID for the given tool. How the value is interpreted depends
388 on the tool type.
389 ****************************************************************************/
390 void editor_tool_set_value(enum editor_tool_type ett, int value)
392 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
393 || !editor_tool_has_value(ett)) {
394 return;
396 editor->tools[ett].value = value;
399 /****************************************************************************
400 Get the current tool sub-value.
401 ****************************************************************************/
402 int editor_tool_get_value(enum editor_tool_type ett)
404 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
405 || !editor_tool_has_value(ett)) {
406 return 0;
409 return editor->tools[ett].value;
412 /****************************************************************************
413 Record the start of the selection rectangle.
414 ****************************************************************************/
415 static void editor_start_selection_rectangle(int canvas_x, int canvas_y)
417 if (!editor) {
418 return;
421 if (editor->selection_mode == SELECTION_MODE_NEW
422 && editor_selection_count() > 0) {
423 editor_selection_clear();
424 update_map_canvas_visible();
427 editor->selrect_start_x = canvas_x;
428 editor->selrect_start_y = canvas_y;
429 editor->selrect_width = 0;
430 editor->selrect_height = 0;
431 editor->selrect_active = TRUE;
434 /****************************************************************************
435 Temporary convenience function to work-around the fact that certain
436 special values (S_RESOURCE_VALID) do not in fact
437 correspond to drawable special types.
438 ****************************************************************************/
439 static inline bool tile_really_has_any_specials(const struct tile *ptile)
441 if (!ptile) {
442 return FALSE;
445 extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
446 if (tile_has_extra(ptile, pextra)) {
447 return TRUE;
449 } extra_type_by_cause_iterate_end;
451 return FALSE;
454 /****************************************************************************
455 Set the editor's current applied player number according to what exists
456 on the given tile.
457 ****************************************************************************/
458 static void editor_grab_applied_player(const struct tile *ptile)
460 int apno = -1;
462 if (!editor || !ptile) {
463 return;
466 if (client_has_player()
467 && tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
468 return;
471 if (tile_city(ptile) != NULL) {
472 apno = player_number(city_owner(tile_city(ptile)));
473 } else if (unit_list_size(ptile->units) > 0) {
474 struct unit *punit = unit_list_get(ptile->units, 0);
475 apno = player_number(unit_owner(punit));
476 } else if (tile_owner(ptile) != NULL) {
477 apno = player_number(tile_owner(ptile));
480 if (player_by_number(apno) != NULL) {
481 editor_tool_set_applied_player(editor_get_tool(), apno);
482 editgui_refresh();
486 /****************************************************************************
487 Set the editor's current tool according to what exists at the given tile.
488 ****************************************************************************/
489 static void editor_grab_tool(const struct tile *ptile)
491 int ett = -1, value = 0;
492 struct extra_type *first_base = NULL;
493 struct extra_type *first_road = NULL;
495 if (!editor) {
496 return;
499 if (!ptile) {
500 return;
503 extra_type_by_cause_iterate(EC_BASE, pextra) {
504 if (tile_has_extra(ptile, pextra)) {
505 first_base = pextra;
506 break;
508 } extra_type_by_cause_iterate_end;
510 extra_type_by_cause_iterate(EC_ROAD, pextra) {
511 if (tile_has_extra(ptile, pextra)) {
512 first_road = pextra;
513 break;
515 } extra_type_by_cause_iterate_end;
517 if (client_has_player()
518 && tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
519 ett = ETT_VISION;
521 } else if (tile_city(ptile)) {
522 ett = ETT_CITY;
524 } else if (unit_list_size(ptile->units) > 0) {
525 int max_score = 0, score;
526 struct unit *grabbed_punit = NULL;
528 unit_list_iterate(ptile->units, punit) {
529 score = 0;
530 if (uclass_has_flag(unit_class_get(punit), UCF_UNREACHABLE)) {
531 score = 5;
532 } else if (utype_move_type(unit_type_get(punit)) == UMT_LAND) {
533 score = 4;
534 } else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
535 score = 3;
536 } else {
537 score = 2;
539 if (unit_transported(punit)) {
540 score = 1;
543 if (score > max_score) {
544 max_score = score;
545 grabbed_punit = punit;
547 } unit_list_iterate_end;
549 if (grabbed_punit) {
550 ett = ETT_UNIT;
551 value = utype_number(unit_type_get(grabbed_punit));
553 } else if (first_base != NULL) {
554 ett = ETT_MILITARY_BASE;
555 value = extra_index(first_base);
557 } else if (first_road != NULL) {
558 ett = ETT_ROAD;
559 value = extra_index(first_road);
561 } else if (tile_really_has_any_specials(ptile)) {
562 struct extra_type *specials_array[MAX_EXTRA_TYPES];
563 int count = 0, i;
564 struct extra_type *special = NULL;
566 extra_type_by_cause_iterate(EC_SPECIAL, s) {
567 specials_array[count++] = s;
568 } extra_type_by_cause_iterate_end;
570 /* Grab specials in reverse order of enum tile_special_type. */
572 for (i = count - 1; i >= 0; i--) {
573 if (tile_has_extra(ptile, specials_array[i])) {
574 special = specials_array[i];
575 break;
579 if (special != NULL) {
580 ett = ETT_TERRAIN_SPECIAL;
581 value = extra_index(special);
583 } else if (tile_resource(ptile) != NULL) {
584 ett = ETT_TERRAIN_RESOURCE;
585 value = resource_number(tile_resource(ptile));
587 } else if (tile_terrain(ptile) != NULL) {
588 ett = ETT_TERRAIN;
589 value = terrain_number(tile_terrain(ptile));
592 if (ett < 0) {
593 return;
596 editor_set_tool(ett);
597 if (editor_tool_has_value(ett)) {
598 editor_tool_set_value(ett, value);
600 editgui_refresh();
603 /****************************************************************************
604 Returns TRUE if the given tile has some objects with editable properties.
605 ****************************************************************************/
606 static inline bool can_edit_tile_properties(struct tile *ptile)
608 return ptile != NULL;
611 /****************************************************************************
612 Handle a request to edit the properties for the given tile. If the tile
613 is part of a selection, then all selected tiles are passed to the
614 property editor.
615 ****************************************************************************/
616 static void popup_properties(struct tile *ptile)
618 struct tile_list *tiles;
620 if (!ptile) {
621 return;
624 tiles = tile_list_new();
626 if (editor_tile_is_selected(ptile)) {
627 tile_hash_iterate(editor->selected_tile_table, sel_tile) {
628 if (can_edit_tile_properties(sel_tile)) {
629 tile_list_append(tiles, sel_tile);
631 } tile_hash_iterate_end;
632 } else {
633 if (can_edit_tile_properties(ptile)) {
634 tile_list_append(tiles, ptile);
638 editgui_popup_properties(tiles, NUM_OBJTYPES);
640 tile_list_destroy(tiles);
643 /****************************************************************************
644 Handle a user's mouse button press at the given point on the map canvas.
645 ****************************************************************************/
646 void editor_mouse_button_press(int canvas_x, int canvas_y,
647 int button, int modifiers)
649 struct tile *ptile;
651 if (editor == NULL) {
652 return;
655 ptile = canvas_pos_to_tile(canvas_x, canvas_y);
656 if (ptile == NULL) {
657 return;
660 switch (button) {
662 case MOUSE_BUTTON_LEFT:
663 if (modifiers == EKM_SHIFT) {
664 editor_grab_tool(ptile);
665 } else if (modifiers == EKM_CTRL) {
666 editor_grab_applied_player(ptile);
667 } else if (modifiers == EKM_NONE) {
668 editor->tool_active = TRUE;
669 editor_apply_tool(ptile, FALSE);
670 editor_notify_edit_finished();
671 editor_set_current_tile(ptile);
673 break;
675 case MOUSE_BUTTON_RIGHT:
676 if (modifiers == (EKM_ALT | EKM_CTRL)) {
677 popup_properties(ptile);
678 break;
681 if (modifiers == EKM_SHIFT) {
682 editor->selection_mode = SELECTION_MODE_ADD;
683 } else if (modifiers == EKM_ALT) {
684 editor->selection_mode = SELECTION_MODE_REMOVE;
685 } else if (modifiers == EKM_NONE) {
686 editor->selection_mode = SELECTION_MODE_NEW;
687 } else {
688 break;
690 editor_start_selection_rectangle(canvas_x, canvas_y);
691 break;
693 case MOUSE_BUTTON_MIDDLE:
694 if (modifiers == EKM_NONE) {
695 popup_properties(ptile);
697 break;
699 default:
700 break;
704 /****************************************************************************
705 Record and handle the end of the selection rectangle.
706 ****************************************************************************/
707 static void editor_end_selection_rectangle(int canvas_x, int canvas_y)
709 int w, h;
711 if (!editor) {
712 return;
715 editor->selrect_active = FALSE;
717 if (editor->selrect_width <= 0 || editor->selrect_height <= 0) {
718 struct tile *ptile;
720 ptile = canvas_pos_to_tile(canvas_x, canvas_y);
721 if (ptile && editor->selection_mode == SELECTION_MODE_ADD) {
722 editor_selection_add(ptile);
723 } else if (ptile && editor->selection_mode == SELECTION_MODE_REMOVE) {
724 editor_selection_remove(ptile);
725 } else {
726 recenter_button_pressed(canvas_x, canvas_y);
727 return;
730 if (ptile) {
731 refresh_tile_mapcanvas(ptile, TRUE, TRUE);
734 return;
737 gui_rect_iterate(mapview.gui_x0 + editor->selrect_x,
738 mapview.gui_y0 + editor->selrect_y,
739 editor->selrect_width, editor->selrect_height,
740 ptile, pedge, pcorner, map_zoom) {
741 if (ptile == NULL) {
742 continue;
744 if (editor->selection_mode == SELECTION_MODE_NEW
745 || editor->selection_mode == SELECTION_MODE_ADD) {
746 editor_selection_add(ptile);
747 } else if (editor->selection_mode == SELECTION_MODE_REMOVE) {
748 editor_selection_remove(ptile);
750 } gui_rect_iterate_end;
752 w = tileset_tile_width(tileset);
753 h = tileset_tile_height(tileset);
755 update_map_canvas(editor->selrect_x - w,
756 editor->selrect_y - h,
757 editor->selrect_width + 2 * w,
758 editor->selrect_height + 2 * h);
759 flush_dirty();
762 /****************************************************************************
763 Draws the editor selection rectangle using draw_selection_rectangle().
764 ****************************************************************************/
765 static void editor_draw_selrect(void)
767 if (!editor) {
768 return;
771 if (editor->selrect_active && editor->selrect_width > 0
772 && editor->selrect_height > 0) {
773 draw_selection_rectangle(editor->selrect_x,
774 editor->selrect_y,
775 editor->selrect_width,
776 editor->selrect_height);
780 /****************************************************************************
781 Handle the release of a mouse button click.
782 ****************************************************************************/
783 void editor_mouse_button_release(int canvas_x, int canvas_y,
784 int button, int modifiers)
786 switch (button) {
788 case MOUSE_BUTTON_LEFT:
789 editor_set_current_tile(NULL);
790 editor->tool_active = FALSE;
791 break;
793 case MOUSE_BUTTON_RIGHT:
794 if (editor->selrect_active) {
795 editor_end_selection_rectangle(canvas_x, canvas_y);
797 break;
799 case MOUSE_BUTTON_MIDDLE:
800 break;
802 default:
803 break;
807 /****************************************************************************
808 Handle a change in the size of the selection rectangle. The given point
809 is the new extremity of the rectangle.
810 ****************************************************************************/
811 static void editor_resize_selection_rectangle(int canvas_x, int canvas_y)
813 int xl, yt, xr, yb;
815 if (editor->selrect_start_x <= canvas_x) {
816 xl = editor->selrect_start_x;
817 xr = canvas_x;
818 } else {
819 xl = canvas_x;
820 xr = editor->selrect_start_x;
823 if (editor->selrect_start_y <= canvas_y) {
824 yt = editor->selrect_start_y;
825 yb = canvas_y;
826 } else {
827 yt = canvas_y;
828 yb = editor->selrect_start_y;
831 /* Erase the previously drawn rectangle. */
832 editor_draw_selrect();
834 if (xl == xr || yt == yb) {
835 editor->selrect_width = 0;
836 editor->selrect_height = 0;
837 return;
840 editor->selrect_x = xl;
841 editor->selrect_y = yt;
842 editor->selrect_width = xr - xl;
843 editor->selrect_height = yb - yt;
845 editor_draw_selrect();
848 /****************************************************************************
849 Handle the mouse moving over the map canvas.
850 ****************************************************************************/
851 void editor_mouse_move(int canvas_x, int canvas_y, int modifiers)
853 const struct tile *ptile, *old;
855 if (!editor) {
856 return;
859 old = editor_get_current_tile();
860 ptile = canvas_pos_to_tile(canvas_x, canvas_y);
862 if (!ptile) {
863 return;
866 if (editor->tool_active && old != NULL && old != ptile) {
867 editor_apply_tool(ptile, FALSE);
868 editor_notify_edit_finished();
869 editor_set_current_tile(ptile);
872 if (editor->selrect_active) {
873 editor_resize_selection_rectangle(canvas_x, canvas_y);
877 /****************************************************************************
878 Notify the server that a batch of edits has completed. This is used as
879 a hint for the server to now do any checks it has saved while the batch
880 was being processed.
881 ****************************************************************************/
882 void editor_notify_edit_finished(void)
884 send_packet_edit_check_tiles(&client.conn);
887 /****************************************************************************
888 Apply the current editor tool to the given tile. This function is
889 suitable to called over multiple tiles at once. Once the batch of
890 operations is finished you should call editor_notify_edit_finished.
891 The 'part_of_selection' parameter should be TRUE if the tool is
892 being applied to a tile from a selection.
893 ****************************************************************************/
894 void editor_apply_tool(const struct tile *ptile,
895 bool part_of_selection)
897 enum editor_tool_type ett;
898 enum editor_tool_mode etm;
899 int value, size, count, apno, tile, id;
900 bool erase;
901 struct connection *my_conn = &client.conn;
903 if (editor == NULL || ptile == NULL) {
904 return;
907 ett = editor_get_tool();
908 etm = editor_tool_get_mode(ett);
909 size = editor_tool_get_size(ett);
910 count = editor_tool_get_count(ett);
911 value = editor_tool_get_value(ett);
912 apno = editor_tool_get_applied_player(ett);
914 if (ett != ETT_VISION && !client_is_global_observer()
915 && client_has_player()
916 && tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
917 return;
920 if (editor_tool_has_applied_player(ett)
921 && player_by_number(apno) == NULL) {
922 return;
925 if (ett == ETT_COPYPASTE) {
926 struct edit_buffer *ebuf;
927 ebuf = editor_get_copy_buffer();
928 if (etm == ETM_COPY) {
929 if (part_of_selection) {
930 edit_buffer_copy(ebuf, ptile);
931 } else {
932 edit_buffer_clear(ebuf);
933 edit_buffer_copy_square(ebuf, ptile, size);
934 editgui_refresh();
936 } else if (etm == ETM_PAINT || etm == ETM_PASTE) {
937 edit_buffer_paste(ebuf, ptile);
939 return;
942 if (part_of_selection && ett != ETT_CITY) {
943 size = 1;
946 erase = (etm == ETM_ERASE);
947 tile = tile_index(ptile);
949 switch (ett) {
951 case ETT_TERRAIN:
952 dsend_packet_edit_tile_terrain(my_conn, tile, erase ? 0 : value, size);
953 break;
955 case ETT_TERRAIN_RESOURCE:
956 dsend_packet_edit_tile_resource(my_conn, tile,
957 erase ? resource_count() : value,
958 size);
959 break;
961 case ETT_TERRAIN_SPECIAL:
962 case ETT_ROAD:
963 case ETT_MILITARY_BASE:
964 dsend_packet_edit_tile_extra(my_conn, tile, value, erase, size);
965 break;
967 case ETT_UNIT:
968 if (erase) {
969 dsend_packet_edit_unit_remove(my_conn, apno, tile, value, count);
970 } else {
971 dsend_packet_edit_unit_create(my_conn, apno, tile, value, count, 0);
973 break;
975 case ETT_CITY:
976 if (erase) {
977 struct city *pcity = tile_city(ptile);
978 if (pcity != NULL) {
979 id = pcity->id;
980 dsend_packet_edit_city_remove(my_conn, id);
982 } else {
983 dsend_packet_edit_city_create(my_conn, apno, tile, size, 0);
985 break;
987 case ETT_VISION:
988 if (client_has_player()) {
989 id = client_player_number();
990 dsend_packet_edit_player_vision(my_conn, id, tile, !erase, size);
992 break;
994 case ETT_STARTPOS:
995 dsend_packet_edit_startpos(my_conn, tile, erase, 0);
996 break;
998 default:
999 break;
1003 /****************************************************************************
1004 Sets the tile currently assumed to be under the user's mouse pointer.
1005 ****************************************************************************/
1006 void editor_set_current_tile(const struct tile *ptile)
1008 if (editor == NULL) {
1009 return;
1012 editor->current_tile = ptile;
1015 /****************************************************************************
1016 Get the tile that the user's mouse pointer is currently over.
1017 ****************************************************************************/
1018 const struct tile *editor_get_current_tile(void)
1020 if (editor == NULL) {
1021 return NULL;
1024 return editor->current_tile;
1027 /****************************************************************************
1028 Toggle the current tool mode between the given mode and ETM_PAINT (or
1029 ETM_COPY for the copy & paste tool).
1030 ****************************************************************************/
1031 void editor_tool_toggle_mode(enum editor_tool_type ett,
1032 enum editor_tool_mode etm)
1034 if (!editor_tool_has_mode(ett, etm)) {
1035 return;
1037 if (editor_tool_get_mode(ett) == etm) {
1038 editor_tool_set_mode(ett, ett == ETT_COPYPASTE
1039 ? ETM_COPY : ETM_PAINT);
1040 } else {
1041 editor_tool_set_mode(ett, etm);
1045 /****************************************************************************
1046 Set the editor tool mode to the next available mode.
1047 ****************************************************************************/
1048 void editor_tool_cycle_mode(enum editor_tool_type ett)
1050 int mode, count;
1051 bool found = FALSE;
1053 mode = editor_tool_get_mode(ett);
1054 if (!(0 <= mode && mode < NUM_EDITOR_TOOL_MODES)) {
1055 return;
1058 for (count = 0; count < NUM_EDITOR_TOOL_MODES; count++) {
1059 mode = (mode + 1) % NUM_EDITOR_TOOL_MODES;
1060 if (editor_tool_has_mode(ett, mode)) {
1061 found = TRUE;
1062 break;
1066 if (found) {
1067 editor_tool_set_mode(ett, mode);
1071 /****************************************************************************
1072 Unselect all selected tiles.
1073 ****************************************************************************/
1074 void editor_selection_clear(void)
1076 if (!editor) {
1077 return;
1079 tile_hash_clear(editor->selected_tile_table);
1082 /****************************************************************************
1083 Add the given tile to the current selection.
1084 ****************************************************************************/
1085 void editor_selection_add(const struct tile *ptile)
1087 if (!editor || !ptile) {
1088 return;
1090 tile_hash_insert(editor->selected_tile_table, ptile, NULL);
1093 /****************************************************************************
1094 Remove the given tile from the current selection.
1095 ****************************************************************************/
1096 void editor_selection_remove(const struct tile *ptile)
1098 if (!editor || !ptile) {
1099 return;
1101 tile_hash_remove(editor->selected_tile_table, ptile);
1104 /****************************************************************************
1105 Returns TRUE if the given tile is selected.
1106 ****************************************************************************/
1107 bool editor_tile_is_selected(const struct tile *ptile)
1109 if (!editor || !ptile) {
1110 return FALSE;
1112 return tile_hash_lookup(editor->selected_tile_table, ptile, NULL);
1115 /****************************************************************************
1116 Apply the current editor tool to all tiles in the current selection.
1117 ****************************************************************************/
1118 void editor_apply_tool_to_selection(void)
1120 enum editor_tool_type ett;
1122 if (!editor || editor_selection_count() <= 0) {
1123 return;
1126 ett = editor_get_tool();
1127 if (editor_tool_get_mode(ett) == ETM_COPY) {
1128 struct edit_buffer *ebuf;
1129 ebuf = editor_get_copy_buffer();
1130 edit_buffer_clear(ebuf);
1131 edit_buffer_set_origin(ebuf, editor_get_selection_center());
1134 connection_do_buffer(&client.conn);
1135 tile_hash_iterate(editor->selected_tile_table, ptile) {
1136 editor_apply_tool(ptile, TRUE);
1137 } tile_hash_iterate_end;
1138 editor_notify_edit_finished();
1139 connection_do_unbuffer(&client.conn);
1141 if (editor_tool_get_mode(ett) == ETM_COPY) {
1142 editgui_refresh();
1146 /****************************************************************************
1147 Get the translated name of the given tool type.
1148 ****************************************************************************/
1149 const char *editor_tool_get_name(enum editor_tool_type ett)
1151 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1152 return "";
1155 return editor->tools[ett].name;
1158 /****************************************************************************
1159 Get the translated name of the given tool value. If no such name exists,
1160 returns an empty string.
1161 ****************************************************************************/
1162 const char *editor_tool_get_value_name(enum editor_tool_type emt, int value)
1164 struct terrain *pterrain;
1165 struct resource *presource;
1166 struct unit_type *putype;
1167 struct extra_type *pextra;
1169 if (!editor) {
1170 return "";
1173 switch (emt) {
1174 case ETT_TERRAIN:
1175 pterrain = terrain_by_number(value);
1176 return pterrain ? terrain_name_translation(pterrain) : "";
1177 break;
1178 case ETT_TERRAIN_RESOURCE:
1179 presource = resource_by_number(value);
1180 return presource ? resource_name_translation(presource) : "";
1181 break;
1182 case ETT_TERRAIN_SPECIAL:
1183 case ETT_ROAD:
1184 case ETT_MILITARY_BASE:
1185 pextra = extra_by_number(value);
1186 return pextra != NULL ? extra_name_translation(pextra) : "";
1187 break;
1188 case ETT_UNIT:
1189 putype = utype_by_number(value);
1190 return putype ? utype_name_translation(putype) : "";
1191 break;
1192 default:
1193 break;
1195 return "";
1198 /****************************************************************************
1199 Return TRUE if the given editor tool uses the 'size' parameter.
1200 ****************************************************************************/
1201 bool editor_tool_has_size(enum editor_tool_type ett)
1203 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1204 return FALSE;
1206 return editor->tools[ett].flags & ETF_HAS_SIZE;
1209 /****************************************************************************
1210 Returns the current size parameter for the given editor tools.
1211 ****************************************************************************/
1212 int editor_tool_get_size(enum editor_tool_type ett)
1214 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1215 return 1;
1217 return editor->tools[ett].size;
1220 /****************************************************************************
1221 Sets the size parameter for the given tool.
1222 ****************************************************************************/
1223 void editor_tool_set_size(enum editor_tool_type ett, int size)
1225 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1226 return;
1228 editor->tools[ett].size = MAX(1, size);
1231 /****************************************************************************
1232 Return TRUE if it is meaningful for the given tool to use the 'count'
1233 parameter.
1234 ****************************************************************************/
1235 bool editor_tool_has_count(enum editor_tool_type ett)
1237 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1238 return FALSE;
1240 return editor->tools[ett].flags & ETF_HAS_COUNT;
1243 /****************************************************************************
1244 Returns the 'count' parameter for the editor tool.
1245 ****************************************************************************/
1246 int editor_tool_get_count(enum editor_tool_type ett)
1248 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1249 return 1;
1251 return editor->tools[ett].count;
1254 /****************************************************************************
1255 Sets the 'count' parameter of the tool to the given value.
1256 ****************************************************************************/
1257 void editor_tool_set_count(enum editor_tool_type ett, int count)
1259 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1260 return;
1262 editor->tools[ett].count = MAX(1, count);
1265 /****************************************************************************
1266 Returns a sprite containing an icon for the given tool type. Returns
1267 NULL if no such sprite exists.
1268 ****************************************************************************/
1269 struct sprite *editor_tool_get_sprite(enum editor_tool_type ett)
1271 const struct editor_sprites *sprites;
1273 if (!tileset || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1274 return NULL;
1277 sprites = get_editor_sprites(tileset);
1278 if (!sprites) {
1279 return NULL;
1282 switch (ett) {
1283 case ETT_COPYPASTE:
1284 return sprites->copypaste;
1285 break;
1286 case ETT_TERRAIN:
1287 return sprites->terrain;
1288 break;
1289 case ETT_TERRAIN_RESOURCE:
1290 return sprites->terrain_resource;
1291 break;
1292 case ETT_TERRAIN_SPECIAL:
1293 return sprites->terrain_special;
1294 break;
1295 case ETT_ROAD:
1296 return sprites->road;
1297 case ETT_MILITARY_BASE:
1298 return sprites->military_base;
1299 case ETT_UNIT:
1300 return sprites->unit;
1301 break;
1302 case ETT_CITY:
1303 return sprites->city;
1304 break;
1305 case ETT_VISION:
1306 return sprites->vision;
1307 break;
1308 case ETT_STARTPOS:
1309 return sprites->startpos;
1310 break;
1311 default:
1312 break;
1315 return NULL;
1318 /****************************************************************************
1319 Returns a translated "tooltip" description for the given tool type.
1320 ****************************************************************************/
1321 const char *editor_tool_get_tooltip(enum editor_tool_type ett)
1323 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
1324 || !editor->tools[ett].tooltip) {
1325 return "";
1327 return editor->tools[ett].tooltip;
1330 /****************************************************************************
1331 Returns the current applied player number for the editor tool.
1333 May return a player number for which player_by_number returns NULL.
1334 ****************************************************************************/
1335 int editor_tool_get_applied_player(enum editor_tool_type ett)
1337 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1338 return -1;
1340 return editor->tools[ett].applied_player_no;
1343 /****************************************************************************
1344 Sets the editor tool's applied player number to the given value.
1345 ****************************************************************************/
1346 void editor_tool_set_applied_player(enum editor_tool_type ett,
1347 int player_no)
1349 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1350 return;
1352 editor->tools[ett].applied_player_no = player_no;
1355 /****************************************************************************
1356 Returns TRUE if the given tool makes use of the editor's applied player
1357 number.
1358 ****************************************************************************/
1359 bool editor_tool_has_applied_player(enum editor_tool_type ett)
1361 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1362 return FALSE;
1364 return editor->tools[ett].flags & ETF_HAS_APPLIED_PLAYER;
1367 /****************************************************************************
1368 Returns TRUE if erase mode for the given tool erases by sub-value instead
1369 of any object corresponding to the tool type.
1370 ****************************************************************************/
1371 bool editor_tool_has_value_erase(enum editor_tool_type ett)
1373 if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1374 return FALSE;
1376 return editor->tools[ett].flags & ETF_HAS_VALUE_ERASE;
1379 /****************************************************************************
1380 Returns the number of currently selected tiles.
1381 ****************************************************************************/
1382 int editor_selection_count(void)
1384 if (!editor) {
1385 return 0;
1387 return tile_hash_size(editor->selected_tile_table);
1390 /****************************************************************************
1391 Creates a virtual unit (like unit_virtual_create) based on the current
1392 editor state. You should free() the unit when it is no longer needed.
1393 If creation is not possible, then NULL is returned.
1395 The virtual unit has no homecity or tile. It is owned by the player
1396 corresponding to the current 'applied player' parameter and has unit type
1397 given by the sub-value of the unit tool (ETT_UNIT).
1398 ****************************************************************************/
1399 struct unit *editor_unit_virtual_create(void)
1401 struct unit *vunit;
1402 struct player *pplayer;
1403 struct unit_type *putype;
1404 int apno, value;
1406 value = editor_tool_get_value(ETT_UNIT);
1407 putype = utype_by_number(value);
1409 if (!putype) {
1410 return NULL;
1413 apno = editor_tool_get_applied_player(ETT_UNIT);
1414 pplayer = player_by_number(apno);
1415 if (!pplayer) {
1416 return NULL;
1419 vunit = unit_virtual_create(pplayer, NULL, putype, 0);
1421 return vunit;
1424 /****************************************************************************
1425 Create a new edit buffer corresponding to all types set in 'type_flags'.
1426 ****************************************************************************/
1427 struct edit_buffer *edit_buffer_new(int type_flags)
1429 struct edit_buffer *ebuf;
1431 if (!(0 <= type_flags && type_flags <= EBT_ALL)) {
1432 return NULL;
1435 ebuf = fc_calloc(1, sizeof(*ebuf));
1436 ebuf->type_flags = type_flags;
1437 ebuf->vtiles = tile_list_new();
1439 return ebuf;
1442 /****************************************************************************
1443 Free all memory allocated for the edit buffer.
1444 ****************************************************************************/
1445 void edit_buffer_free(struct edit_buffer *ebuf)
1447 if (!ebuf) {
1448 return;
1451 if (ebuf->vtiles) {
1452 tile_list_iterate(ebuf->vtiles, vtile) {
1453 tile_virtual_destroy(vtile);
1454 } tile_list_iterate_end;
1455 tile_list_destroy(ebuf->vtiles);
1456 ebuf->vtiles = NULL;
1458 free(ebuf);
1461 /****************************************************************************
1462 Remove all copy data stored in the edit buffer.
1463 ****************************************************************************/
1464 void edit_buffer_clear(struct edit_buffer *ebuf)
1466 if (!ebuf || !ebuf->vtiles) {
1467 return;
1470 tile_list_iterate(ebuf->vtiles, vtile) {
1471 tile_virtual_destroy(vtile);
1472 } tile_list_iterate_end;
1473 tile_list_clear(ebuf->vtiles);
1475 edit_buffer_set_origin(ebuf, NULL);
1478 /****************************************************************************
1479 Copy from a square region of half-width 'radius' centered around 'center'
1480 into the buffer.
1481 ****************************************************************************/
1482 void edit_buffer_copy_square(struct edit_buffer *ebuf,
1483 const struct tile *center,
1484 int radius)
1486 if (!ebuf || !center || radius < 1) {
1487 return;
1490 edit_buffer_set_origin(ebuf, center);
1491 square_iterate(center, radius - 1, ptile) {
1492 edit_buffer_copy(ebuf, ptile);
1493 } square_iterate_end;
1496 /****************************************************************************
1497 Append a single tile to the copy buffer.
1498 ****************************************************************************/
1499 void edit_buffer_copy(struct edit_buffer *ebuf, const struct tile *ptile)
1501 struct tile *vtile;
1502 struct unit *vunit;
1503 bool copied = FALSE;
1505 if (!ebuf || !ptile) {
1506 return;
1509 vtile = tile_virtual_new(NULL);
1510 vtile->index = tile_index(ptile);
1512 edit_buffer_type_iterate(ebuf, type) {
1513 switch (type) {
1514 case EBT_TERRAIN:
1515 if (tile_terrain(ptile)) {
1516 tile_set_terrain(vtile, tile_terrain(ptile));
1517 copied = TRUE;
1519 break;
1520 case EBT_RESOURCE:
1521 if (tile_resource(ptile)) {
1522 tile_set_resource(vtile, tile_resource(ptile));
1523 copied = TRUE;
1525 break;
1526 case EBT_SPECIAL:
1527 extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
1528 if (tile_has_extra(ptile, pextra)) {
1529 tile_add_extra(vtile, pextra);
1530 copied = TRUE;
1532 } extra_type_by_cause_iterate_end;
1533 break;
1534 case EBT_BASE:
1535 extra_type_iterate(pextra) {
1536 if (tile_has_extra(ptile, pextra)
1537 && is_extra_caused_by(pextra, EC_BASE)) {
1538 tile_add_extra(vtile, pextra);
1539 copied = TRUE;
1541 } extra_type_iterate_end;
1542 case EBT_ROAD:
1543 extra_type_iterate(pextra) {
1544 if (tile_has_extra(ptile, pextra)
1545 && is_extra_caused_by(pextra, EC_ROAD)) {
1546 tile_add_extra(vtile, pextra);
1547 copied = TRUE;
1549 } extra_type_iterate_end;
1550 case EBT_UNIT:
1551 unit_list_iterate(ptile->units, punit) {
1552 if (!punit) {
1553 continue;
1555 vunit = unit_virtual_create(unit_owner(punit), NULL,
1556 unit_type_get(punit), punit->veteran);
1557 vunit->homecity = punit->homecity;
1558 vunit->hp = punit->hp;
1559 unit_list_append(vtile->units, vunit);
1560 copied = TRUE;
1561 } unit_list_iterate_end;
1562 break;
1563 case EBT_CITY:
1564 if (tile_city(ptile)) {
1565 struct city *pcity, *vcity;
1566 char name[MAX_LEN_NAME];
1568 pcity = tile_city(ptile);
1569 fc_snprintf(name, sizeof(name), "Copy of %s",
1570 city_name_get(pcity));
1571 vcity = create_city_virtual(city_owner(pcity), NULL, name);
1572 city_size_set(vcity, city_size_get(pcity));
1573 improvement_iterate(pimprove) {
1574 if (!is_improvement(pimprove)
1575 || !city_has_building(pcity, pimprove)) {
1576 continue;
1578 city_add_improvement(vcity, pimprove);
1579 } improvement_iterate_end;
1580 tile_set_worked(vtile, vcity);
1581 copied = TRUE;
1583 break;
1584 default:
1585 break;
1587 } edit_buffer_type_iterate_end;
1589 if (copied) {
1590 tile_list_append(ebuf->vtiles, vtile);
1591 } else {
1592 tile_virtual_destroy(vtile);
1596 /****************************************************************************
1597 Helper function to fill in an edit packet with the tile's current values.
1598 ****************************************************************************/
1599 static void fill_tile_edit_packet(struct packet_edit_tile *packet,
1600 const struct tile *ptile)
1602 const struct resource *presource;
1603 const struct terrain *pterrain;
1605 if (!packet || !ptile) {
1606 return;
1608 packet->tile = tile_index(ptile);
1609 packet->extras = *tile_extras(ptile);
1611 presource = tile_resource(ptile);
1612 packet->resource = presource
1613 ? resource_number(presource)
1614 : resource_count();
1616 pterrain = tile_terrain(ptile);
1617 packet->terrain = pterrain
1618 ? terrain_number(pterrain)
1619 : terrain_count();
1621 if (ptile->label == NULL) {
1622 packet->label[0] = '\0';
1623 } else {
1624 strncpy(packet->label, ptile->label, sizeof(packet->label));
1628 /****************************************************************************
1629 Helper function for edit_buffer_paste(). Do a single paste of the stuff set
1630 in the buffer on the virtual tile to the destination tile 'ptile_dest'.
1631 ****************************************************************************/
1632 static void paste_tile(struct edit_buffer *ebuf,
1633 const struct tile *vtile,
1634 const struct tile *ptile_dest)
1636 struct connection *my_conn = &client.conn;
1637 struct packet_edit_tile tile_packet;
1638 struct city *vcity;
1639 int value, owner, tile;
1640 bool send_edit_tile = FALSE;
1642 if (!ebuf || !vtile || !ptile_dest) {
1643 return;
1646 tile = tile_index(ptile_dest);
1648 fill_tile_edit_packet(&tile_packet, ptile_dest);
1650 edit_buffer_type_iterate(ebuf, type) {
1651 switch (type) {
1652 case EBT_TERRAIN:
1653 if (!tile_terrain(vtile)) {
1654 continue;
1656 value = terrain_number(tile_terrain(vtile));
1657 dsend_packet_edit_tile_terrain(my_conn, tile, value, 1);
1658 break;
1659 case EBT_RESOURCE:
1660 if (!tile_resource(vtile)) {
1661 continue;
1663 value = resource_number(tile_resource(vtile));
1664 dsend_packet_edit_tile_resource(my_conn, tile, value, 1);
1665 break;
1666 case EBT_SPECIAL:
1667 extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
1668 if (tile_has_extra(vtile, pextra)) {
1669 BV_SET(tile_packet.extras, extra_index(pextra));
1670 send_edit_tile = TRUE;
1672 } extra_type_by_cause_iterate_end;
1673 break;
1674 case EBT_BASE:
1675 extra_type_iterate(pextra) {
1676 if (tile_has_extra(vtile, pextra)
1677 && is_extra_caused_by(pextra, EC_BASE)) {
1678 BV_SET(tile_packet.extras, extra_index(pextra));
1679 send_edit_tile = TRUE;
1681 } extra_type_iterate_end;
1682 break;
1683 case EBT_ROAD:
1684 extra_type_iterate(pextra) {
1685 if (tile_has_extra(vtile, pextra)
1686 && is_extra_caused_by(pextra, EC_ROAD)) {
1687 BV_SET(tile_packet.extras, extra_index(pextra));
1688 send_edit_tile = TRUE;
1690 } extra_type_iterate_end;
1691 break;
1692 case EBT_UNIT:
1693 unit_list_iterate(vtile->units, vunit) {
1694 value = utype_number(unit_type_get(vunit));
1695 owner = player_number(unit_owner(vunit));
1696 dsend_packet_edit_unit_create(my_conn, owner, tile, value, 1, 0);
1697 } unit_list_iterate_end;
1698 break;
1699 case EBT_CITY:
1700 vcity = tile_city(vtile);
1701 if (!vcity) {
1702 continue;
1704 owner = player_number(city_owner(vcity));
1705 value = city_size_get(vcity);
1706 dsend_packet_edit_city_create(my_conn, owner, tile, value, 0);
1707 break;
1708 default:
1709 break;
1711 } edit_buffer_type_iterate_end;
1713 if (send_edit_tile) {
1714 send_packet_edit_tile(my_conn, &tile_packet);
1718 /****************************************************************************
1719 Paste the entire contents of the edit buffer using 'dest' as the origin.
1720 ****************************************************************************/
1721 void edit_buffer_paste(struct edit_buffer *ebuf, const struct tile *dest)
1723 struct connection *my_conn = &client.conn;
1724 const struct tile *origin, *ptile;
1725 int dx, dy;
1727 if (!ebuf || !dest) {
1728 return;
1731 /* Calculate vector. */
1732 origin = edit_buffer_get_origin(ebuf);
1733 fc_assert_ret(origin != NULL);
1734 map_distance_vector(&dx, &dy, origin, dest);
1736 connection_do_buffer(my_conn);
1737 tile_list_iterate(ebuf->vtiles, vtile) {
1738 int virt_x, virt_y;
1740 index_to_map_pos(&virt_x, &virt_y, tile_index(vtile));
1741 ptile = map_pos_to_tile(virt_x + dx, virt_y + dy);
1742 if (!ptile) {
1743 continue;
1745 paste_tile(ebuf, vtile, ptile);
1746 } tile_list_iterate_end;
1747 connection_do_unbuffer(my_conn);
1750 /****************************************************************************
1751 Returns the copy buffer for the given tool.
1752 ****************************************************************************/
1753 struct edit_buffer *editor_get_copy_buffer(void)
1755 if (!editor) {
1756 return NULL;
1758 return editor->copybuf;
1761 /****************************************************************************
1762 Returns the translated string name for the given mode.
1763 ****************************************************************************/
1764 const char *editor_tool_get_mode_name(enum editor_tool_type ett,
1765 enum editor_tool_mode etm)
1767 bool value_erase;
1769 value_erase = editor_tool_has_value_erase(ett);
1771 switch (etm) {
1772 case ETM_PAINT:
1773 return _("Paint");
1774 break;
1775 case ETM_ERASE:
1776 if (value_erase) {
1777 return _("Erase Value");
1778 } else {
1779 return _("Erase");
1781 break;
1782 case ETM_COPY:
1783 return _("Copy");
1784 break;
1785 case ETM_PASTE:
1786 return _("Paste");
1787 break;
1788 default:
1789 log_error("Unrecognized editor tool mode %d "
1790 "in editor_tool_get_mode_name().", etm);
1791 break;
1794 return "";
1797 /****************************************************************************
1798 Returns a translated tooltip string assumed to be used for the toggle
1799 button for this tool mode in the editor gui.
1800 ****************************************************************************/
1801 const char *editor_get_mode_tooltip(enum editor_tool_mode etm)
1803 switch (etm) {
1804 case ETM_ERASE:
1805 return _("Toggle erase mode.\nShortcut: shift-d");
1806 break;
1807 case ETM_COPY:
1808 return _("Toggle copy mode.\nShortcut: shift-c");
1809 break;
1810 case ETM_PASTE:
1811 return _("Toggle paste mode.\nShortcut: shift-v");
1812 break;
1813 default:
1814 break;
1817 return NULL;
1820 /****************************************************************************
1821 Returns the editor sprite corresponding to the tool mode.
1822 ****************************************************************************/
1823 struct sprite *editor_get_mode_sprite(enum editor_tool_mode etm)
1825 const struct editor_sprites *sprites;
1827 sprites = get_editor_sprites(tileset);
1828 if (!sprites) {
1829 return NULL;
1832 switch (etm) {
1833 case ETM_PAINT:
1834 return sprites->brush;
1835 break;
1836 case ETM_ERASE:
1837 return sprites->erase;
1838 break;
1839 case ETM_COPY:
1840 return sprites->copy;
1841 break;
1842 case ETM_PASTE:
1843 return sprites->paste;
1844 break;
1845 default:
1846 break;
1849 return NULL;
1852 /****************************************************************************
1853 Fill the supplied buffer with a translated string describing the edit
1854 buffer's current state. Returns the number of bytes used.
1855 ****************************************************************************/
1856 int edit_buffer_get_status_string(const struct edit_buffer *ebuf,
1857 char *buf, int buflen)
1859 int ret, total;
1860 const char *fmt;
1862 if (!buf || buflen < 1) {
1863 return 0;
1866 ret = fc_strlcpy(buf, _("Buffer empty."), buflen);
1867 if (!ebuf || !ebuf->vtiles) {
1868 return ret;
1871 total = tile_list_size(ebuf->vtiles);
1872 if (total > 0) {
1873 fmt = PL_("%d tile copied.", "%d tiles copied.", total);
1874 ret = fc_snprintf(buf, buflen, fmt, total);
1877 return ret;
1880 /****************************************************************************
1881 Set the "origin" for subsequent copy operations. This controls the x and
1882 y offset of newly created virtual tiles in the buffer.
1883 ****************************************************************************/
1884 void edit_buffer_set_origin(struct edit_buffer *ebuf,
1885 const struct tile *ptile)
1887 if (!ebuf) {
1888 return;
1890 ebuf->origin = ptile;
1893 /****************************************************************************
1894 Return the previously set origin, or NULL if none.
1895 ****************************************************************************/
1896 const struct tile *edit_buffer_get_origin(const struct edit_buffer *ebuf)
1898 if (!ebuf) {
1899 return NULL;
1901 return ebuf->origin;
1904 /****************************************************************************
1905 Returns TRUE if the edit buffer was created with the given type flag.
1906 ****************************************************************************/
1907 bool edit_buffer_has_type(const struct edit_buffer *ebuf, int type)
1909 if (!ebuf) {
1910 return FALSE;
1912 return ebuf->type_flags & type;
1915 /****************************************************************************
1916 Returns the "center" tile of a group of selected tiles, or NULL.
1917 The center is calculated as the vector sum divided by the number of tiles,
1918 i.e. the average of the map distance vectors of the selected tiles.
1919 ****************************************************************************/
1920 const struct tile *editor_get_selection_center(void)
1922 int count;
1923 const struct tile *origin, *center;
1924 int dx, dy, cx, cy;
1925 int xsum = 0, ysum = 0;
1927 if (!editor || !editor->selected_tile_table) {
1928 return NULL;
1931 count = tile_hash_size(editor->selected_tile_table);
1932 if (count < 1) {
1933 return NULL;
1936 origin = map_pos_to_tile(0, 0);
1937 tile_hash_iterate(editor->selected_tile_table, ptile) {
1938 map_distance_vector(&dx, &dy, origin, ptile);
1939 xsum += dx;
1940 ysum += dy;
1941 } tile_hash_iterate_end;
1943 cx = xsum / count;
1944 cy = ysum / count;
1945 center = map_pos_to_tile(cx, cy);
1947 return center;