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.
7 
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 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdarg.h>
19 #include <string.h>
20 
21 /* utility */
22 #include "bitvector.h"
23 #include "fcintl.h"
24 #include "log.h"
25 #include "support.h"
26 
27 /* common */
28 #include "game.h"
29 #include "map.h"
30 #include "movement.h"
31 #include "packets.h"
32 
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"
41 
42 /* client/include */
43 #include "editgui_g.h"
44 #include "mapview_g.h"
45 
46 
47 enum selection_modes {
48   SELECTION_MODE_NEW = 0,
49   SELECTION_MODE_ADD,
50   SELECTION_MODE_REMOVE
51 };
52 
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
60 };
61 
62 struct edit_buffer {
63   int type_flags;
64   struct tile_list *vtiles;
65   const struct tile *origin;
66 };
67 
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;
77 };
78 
79 struct editor_state {
80   enum editor_tool_type tool;
81   struct editor_tool tools[NUM_EDITOR_TOOL_TYPES];
82 
83   const struct tile *current_tile;
84   bool tool_active;
85 
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;
93 
94   enum selection_modes selection_mode;
95 
96   struct tile_hash *selected_tile_table;
97   struct edit_buffer *copybuf;
98 };
99 
100 static struct editor_state *editor = NULL;
101 
102 /****************************************************************************
103   Set tool to some value legal under current ruleset.
104 ****************************************************************************/
tool_set_init_value(enum editor_tool_type ett)105 static void tool_set_init_value(enum editor_tool_type ett)
106 {
107   struct editor_tool *tool = editor->tools + ett;
108 
109   if (ett == ETT_TERRAIN_SPECIAL
110       || ett == ETT_ROAD
111       || ett == ETT_MILITARY_BASE) {
112     struct extra_type *first = NULL;
113 
114     extra_type_iterate(pextra) {
115       if (ett == ETT_ROAD) {
116         if (is_extra_caused_by(pextra, EC_ROAD)) {
117           first = pextra;
118           break;
119         }
120       } else if (ett == ETT_MILITARY_BASE) {
121         if (is_extra_caused_by(pextra, EC_BASE)) {
122           first = pextra;
123           break;
124         }
125       } else {
126         /* Considers extras that are neither bases or roads, specials */
127         first = pextra;
128         break;
129       }
130     } extra_type_iterate_end;
131 
132     if (first != NULL) {
133       tool->value = extra_index(first);
134     } else {
135       tool->value = 0;
136     }
137   } else {
138     tool->value = 0;
139   }
140 }
141 
142 /****************************************************************************
143   Initialize editor tool data.
144 ****************************************************************************/
tool_init(enum editor_tool_type ett,const char * name,int flags,const char * tooltip)145 static void tool_init(enum editor_tool_type ett, const char *name,
146                       int flags, const char *tooltip)
147 {
148   struct editor_tool *tool;
149 
150   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
151     return;
152   }
153 
154   tool = editor->tools + ett;
155 
156   if (ett == ETT_COPYPASTE) {
157     tool->mode = ETM_COPY;
158   } else {
159     tool->mode = ETM_PAINT;
160   }
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;
167 
168   tool_set_init_value(ett);
169 }
170 
171 /****************************************************************************
172   Adjust editor for changed ruleset.
173 ****************************************************************************/
editor_ruleset_changed(void)174 void editor_ruleset_changed(void)
175 {
176   int t;
177 
178   for (t = 0; t < NUM_EDITOR_TOOL_TYPES; t++) {
179     tool_set_init_value(t);
180   }
181 }
182 
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 ****************************************************************************/
editor_init(void)187 void editor_init(void)
188 {
189   fc_assert(editor == NULL);
190 
191   editor = fc_calloc(1, sizeof(struct editor_state));
192 
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"));
226 
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);
232 
233   editor->selected_tile_table = tile_hash_new();
234   tile_hash_set_no_shrink(editor->selected_tile_table, TRUE);
235 }
236 
237 /****************************************************************************
238   Clear the editor data which is game dependent.
239 ****************************************************************************/
editor_clear(void)240 void editor_clear(void)
241 {
242   fc_assert_ret(editor != NULL);
243 
244   edit_buffer_clear(editor->copybuf);
245   tile_hash_clear(editor->selected_tile_table);
246 }
247 
248 /****************************************************************************
249   Free the client's editor.
250 ****************************************************************************/
editor_free(void)251 void editor_free(void)
252 {
253   if (editor != NULL) {
254     edit_buffer_free(editor->copybuf);
255     tile_hash_destroy(editor->selected_tile_table);
256     free(editor);
257     editor = NULL;
258   }
259 }
260 
261 /****************************************************************************
262   Set the current tool to be used by the editor.
263 ****************************************************************************/
editor_set_tool(enum editor_tool_type ett)264 void editor_set_tool(enum editor_tool_type ett)
265 {
266   if (editor == NULL) {
267     return;
268   }
269 
270   if (!(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
271     return;
272   }
273 
274   editor->tool = ett;
275 }
276 
277 /****************************************************************************
278   Get the current tool used by the editor.
279 ****************************************************************************/
editor_get_tool(void)280 enum editor_tool_type editor_get_tool(void)
281 {
282   if (editor == NULL) {
283     return NUM_EDITOR_TOOL_TYPES;
284   }
285 
286   return editor->tool;
287 }
288 
289 /****************************************************************************
290   Set the mode for the editor tool.
291 ****************************************************************************/
editor_tool_set_mode(enum editor_tool_type ett,enum editor_tool_mode etm)292 void editor_tool_set_mode(enum editor_tool_type ett,
293                           enum editor_tool_mode etm)
294 {
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;
299   }
300 
301   editor->tools[ett].mode = etm;
302 }
303 
304 /****************************************************************************
305   Return TRUE if the given tool supports the given mode.
306 ****************************************************************************/
editor_tool_has_mode(enum editor_tool_type ett,enum editor_tool_mode etm)307 bool editor_tool_has_mode(enum editor_tool_type ett,
308                           enum editor_tool_mode etm)
309 {
310   if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
311       || !(0 <= etm && etm < NUM_EDITOR_TOOL_MODES)) {
312     return FALSE;
313   }
314 
315   if (etm == ETM_COPY || etm == ETM_PASTE) {
316     return ett == ETT_COPYPASTE;
317   }
318 
319   if (ett == ETT_COPYPASTE) {
320     return etm == ETM_COPY || etm == ETM_PASTE;
321   }
322 
323   return TRUE;
324 }
325 
326 /****************************************************************************
327   Get the mode for the tool.
328 ****************************************************************************/
editor_tool_get_mode(enum editor_tool_type ett)329 enum editor_tool_mode editor_tool_get_mode(enum editor_tool_type ett)
330 {
331   if (editor == NULL || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
332     return NUM_EDITOR_TOOL_MODES;
333   }
334   return editor->tools[ett].mode;
335 }
336 
337 /****************************************************************************
338   Returns TRUE if the *client* is in edit mode.
339 ****************************************************************************/
editor_is_active(void)340 bool editor_is_active(void)
341 {
342   return can_conn_edit(&client.conn);
343 }
344 
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.
349 
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 ****************************************************************************/
editor_tool_is_usable(enum editor_tool_type ett)353 bool editor_tool_is_usable(enum editor_tool_type ett)
354 {
355   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
356     return FALSE;
357   }
358 
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;
370   }
371   return TRUE;
372 }
373 
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 ****************************************************************************/
editor_tool_has_value(enum editor_tool_type ett)378 bool editor_tool_has_value(enum editor_tool_type ett)
379 {
380   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
381     return FALSE;
382   }
383   return editor->tools[ett].flags & ETF_HAS_VALUE;
384 }
385 
386 /****************************************************************************
387   Set the value ID for the given tool. How the value is interpreted depends
388   on the tool type.
389 ****************************************************************************/
editor_tool_set_value(enum editor_tool_type ett,int value)390 void editor_tool_set_value(enum editor_tool_type ett, int value)
391 {
392   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
393       || !editor_tool_has_value(ett)) {
394     return;
395   }
396   editor->tools[ett].value = value;
397 }
398 
399 /****************************************************************************
400   Get the current tool sub-value.
401 ****************************************************************************/
editor_tool_get_value(enum editor_tool_type ett)402 int editor_tool_get_value(enum editor_tool_type ett)
403 {
404   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
405       || !editor_tool_has_value(ett)) {
406     return 0;
407   }
408 
409   return editor->tools[ett].value;
410 }
411 
412 /****************************************************************************
413   Record the start of the selection rectangle.
414 ****************************************************************************/
editor_start_selection_rectangle(int canvas_x,int canvas_y)415 static void editor_start_selection_rectangle(int canvas_x, int canvas_y)
416 {
417   if (!editor) {
418     return;
419   }
420 
421   if (editor->selection_mode == SELECTION_MODE_NEW
422       && editor_selection_count() > 0) {
423     editor_selection_clear();
424     update_map_canvas_visible();
425   }
426 
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;
432 }
433 
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 ****************************************************************************/
tile_really_has_any_specials(const struct tile * ptile)439 static inline bool tile_really_has_any_specials(const struct tile *ptile)
440 {
441   if (!ptile) {
442     return FALSE;
443   }
444 
445   extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
446     if (tile_has_extra(ptile, pextra)) {
447       return TRUE;
448     }
449   } extra_type_by_cause_iterate_end;
450 
451   return FALSE;
452 }
453 
454 /****************************************************************************
455   Set the editor's current applied player number according to what exists
456   on the given tile.
457 ****************************************************************************/
editor_grab_applied_player(const struct tile * ptile)458 static void editor_grab_applied_player(const struct tile *ptile)
459 {
460   int apno = -1;
461 
462   if (!editor || !ptile) {
463     return;
464   }
465 
466   if (client_has_player()
467       && tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
468     return;
469   }
470 
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));
478   }
479 
480   if (player_by_number(apno) != NULL) {
481     editor_tool_set_applied_player(editor_get_tool(), apno);
482     editgui_refresh();
483   }
484 }
485 
486 /****************************************************************************
487   Set the editor's current tool according to what exists at the given tile.
488 ****************************************************************************/
editor_grab_tool(const struct tile * ptile)489 static void editor_grab_tool(const struct tile *ptile)
490 {
491   int ett = -1, value = 0;
492   struct extra_type *first_base = NULL;
493   struct extra_type *first_road = NULL;
494 
495   if (!editor) {
496     return;
497   }
498 
499   if (!ptile) {
500     return;
501   }
502 
503   extra_type_by_cause_iterate(EC_BASE, pextra) {
504     if (tile_has_extra(ptile, pextra)) {
505       first_base = pextra;
506       break;
507     }
508   } extra_type_by_cause_iterate_end;
509 
510   extra_type_by_cause_iterate(EC_ROAD, pextra) {
511     if (tile_has_extra(ptile, pextra)) {
512       first_road = pextra;
513       break;
514     }
515   } extra_type_by_cause_iterate_end;
516 
517   if (client_has_player()
518       && tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
519     ett = ETT_VISION;
520 
521   } else if (tile_city(ptile)) {
522     ett = ETT_CITY;
523 
524   } else if (unit_list_size(ptile->units) > 0) {
525     int max_score = 0, score;
526     struct unit *grabbed_punit = NULL;
527 
528     unit_list_iterate(ptile->units, punit) {
529       if (uclass_has_flag(unit_class_get(punit), UCF_UNREACHABLE)) {
530         score = 5;
531       } else if (utype_move_type(unit_type_get(punit)) == UMT_LAND) {
532         score = 4;
533       } else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
534         score = 3;
535       } else {
536         score = 2;
537       }
538       if (unit_transported(punit)) {
539         score = 1;
540       }
541 
542       if (score > max_score) {
543         max_score = score;
544         grabbed_punit = punit;
545       }
546     } unit_list_iterate_end;
547 
548     if (grabbed_punit) {
549       ett = ETT_UNIT;
550       value = utype_number(unit_type_get(grabbed_punit));
551     }
552   } else if (first_base != NULL) {
553     ett = ETT_MILITARY_BASE;
554     value = extra_index(first_base);
555 
556   } else if (first_road != NULL) {
557     ett = ETT_ROAD;
558     value = extra_index(first_road);
559 
560   } else if (tile_really_has_any_specials(ptile)) {
561     struct extra_type *specials_array[MAX_EXTRA_TYPES];
562     int count = 0, i;
563     struct extra_type *special = NULL;
564 
565     extra_type_by_cause_iterate(EC_SPECIAL, s) {
566       specials_array[count++] = s;
567     } extra_type_by_cause_iterate_end;
568 
569     /* Grab specials in reverse order of enum tile_special_type. */
570 
571     for (i = count - 1; i >= 0; i--) {
572       if (tile_has_extra(ptile, specials_array[i])) {
573         special = specials_array[i];
574         break;
575       }
576     }
577 
578     if (special != NULL) {
579       ett = ETT_TERRAIN_SPECIAL;
580       value = extra_index(special);
581     }
582   } else if (tile_resource(ptile) != NULL) {
583     ett = ETT_TERRAIN_RESOURCE;
584     value = resource_number(tile_resource(ptile));
585 
586   } else if (tile_terrain(ptile) != NULL) {
587     ett = ETT_TERRAIN;
588     value = terrain_number(tile_terrain(ptile));
589   }
590 
591   if (ett < 0) {
592     return;
593   }
594 
595   editor_set_tool(ett);
596   if (editor_tool_has_value(ett)) {
597     editor_tool_set_value(ett, value);
598   }
599   editgui_refresh();
600 }
601 
602 /****************************************************************************
603   Returns TRUE if the given tile has some objects with editable properties.
604 ****************************************************************************/
can_edit_tile_properties(struct tile * ptile)605 static inline bool can_edit_tile_properties(struct tile *ptile)
606 {
607   return ptile != NULL;
608 }
609 
610 /****************************************************************************
611   Handle a request to edit the properties for the given tile. If the tile
612   is part of a selection, then all selected tiles are passed to the
613   property editor.
614 ****************************************************************************/
popup_properties(struct tile * ptile)615 static void popup_properties(struct tile *ptile)
616 {
617   struct tile_list *tiles;
618 
619   if (!ptile) {
620     return;
621   }
622 
623   tiles = tile_list_new();
624 
625   if (editor_tile_is_selected(ptile)) {
626     tile_hash_iterate(editor->selected_tile_table, sel_tile) {
627       if (can_edit_tile_properties(sel_tile)) {
628         tile_list_append(tiles, sel_tile);
629       }
630     } tile_hash_iterate_end;
631   } else {
632     if (can_edit_tile_properties(ptile)) {
633       tile_list_append(tiles, ptile);
634     }
635   }
636 
637   editgui_popup_properties(tiles, NUM_OBJTYPES);
638 
639   tile_list_destroy(tiles);
640 }
641 
642 /****************************************************************************
643   Handle a user's mouse button press at the given point on the map canvas.
644 ****************************************************************************/
editor_mouse_button_press(int canvas_x,int canvas_y,int button,int modifiers)645 void editor_mouse_button_press(int canvas_x, int canvas_y,
646                                int button, int modifiers)
647 {
648   struct tile *ptile;
649 
650   if (editor == NULL) {
651     return;
652   }
653 
654   ptile = canvas_pos_to_tile(canvas_x, canvas_y);
655   if (ptile == NULL) {
656     return;
657   }
658 
659   switch (button) {
660 
661   case MOUSE_BUTTON_LEFT:
662     if (modifiers == EKM_SHIFT) {
663       editor_grab_tool(ptile);
664     } else if (modifiers == EKM_CTRL) {
665       editor_grab_applied_player(ptile);
666     } else if (modifiers == EKM_NONE) {
667       editor->tool_active = TRUE;
668       editor_apply_tool(ptile, FALSE);
669       editor_notify_edit_finished();
670       editor_set_current_tile(ptile);
671     }
672     break;
673 
674   case MOUSE_BUTTON_RIGHT:
675     if (modifiers == (EKM_ALT | EKM_CTRL)) {
676       popup_properties(ptile);
677       break;
678     }
679 
680     if (modifiers == EKM_SHIFT) {
681       editor->selection_mode = SELECTION_MODE_ADD;
682     } else if (modifiers == EKM_ALT) {
683       editor->selection_mode = SELECTION_MODE_REMOVE;
684     } else if (modifiers == EKM_NONE) {
685       editor->selection_mode = SELECTION_MODE_NEW;
686     } else {
687       break;
688     }
689     editor_start_selection_rectangle(canvas_x, canvas_y);
690     break;
691 
692   case MOUSE_BUTTON_MIDDLE:
693     if (modifiers == EKM_NONE) {
694       popup_properties(ptile);
695     }
696     break;
697 
698   default:
699     break;
700   }
701 }
702 
703 /****************************************************************************
704   Record and handle the end of the selection rectangle.
705 ****************************************************************************/
editor_end_selection_rectangle(int canvas_x,int canvas_y)706 static void editor_end_selection_rectangle(int canvas_x, int canvas_y)
707 {
708   int w, h;
709 
710   if (!editor) {
711     return;
712   }
713 
714   editor->selrect_active = FALSE;
715 
716   if (editor->selrect_width <= 0 || editor->selrect_height <= 0) {
717     struct tile *ptile;
718 
719     ptile = canvas_pos_to_tile(canvas_x, canvas_y);
720     if (ptile && editor->selection_mode == SELECTION_MODE_ADD) {
721       editor_selection_add(ptile);
722     } else if (ptile && editor->selection_mode == SELECTION_MODE_REMOVE) {
723       editor_selection_remove(ptile);
724     } else {
725       recenter_button_pressed(canvas_x, canvas_y);
726       return;
727     }
728 
729     if (ptile) {
730       refresh_tile_mapcanvas(ptile, TRUE, TRUE);
731     }
732 
733     return;
734   }
735 
736   gui_rect_iterate(mapview.gui_x0 + editor->selrect_x,
737                    mapview.gui_y0 + editor->selrect_y,
738                    editor->selrect_width, editor->selrect_height,
739                    ptile, pedge, pcorner, map_zoom) {
740     if (ptile == NULL) {
741       continue;
742     }
743     if (editor->selection_mode == SELECTION_MODE_NEW
744         || editor->selection_mode == SELECTION_MODE_ADD) {
745       editor_selection_add(ptile);
746     } else if (editor->selection_mode == SELECTION_MODE_REMOVE) {
747       editor_selection_remove(ptile);
748     }
749   } gui_rect_iterate_end;
750 
751   w = tileset_tile_width(tileset);
752   h = tileset_tile_height(tileset);
753 
754   update_map_canvas(editor->selrect_x - w,
755                     editor->selrect_y - h,
756                     editor->selrect_width + 2 * w,
757                     editor->selrect_height + 2 * h);
758   flush_dirty();
759 }
760 
761 /****************************************************************************
762   Draws the editor selection rectangle using draw_selection_rectangle().
763 ****************************************************************************/
editor_draw_selrect(void)764 static void editor_draw_selrect(void)
765 {
766   if (!editor) {
767     return;
768   }
769 
770   if (editor->selrect_active && editor->selrect_width > 0
771       && editor->selrect_height > 0) {
772     draw_selection_rectangle(editor->selrect_x,
773                              editor->selrect_y,
774                              editor->selrect_width,
775                              editor->selrect_height);
776   }
777 }
778 
779 /****************************************************************************
780   Handle the release of a mouse button click.
781 ****************************************************************************/
editor_mouse_button_release(int canvas_x,int canvas_y,int button,int modifiers)782 void editor_mouse_button_release(int canvas_x, int canvas_y,
783                                  int button, int modifiers)
784 {
785   switch (button) {
786 
787   case MOUSE_BUTTON_LEFT:
788     editor_set_current_tile(NULL);
789     editor->tool_active = FALSE;
790     break;
791 
792   case MOUSE_BUTTON_RIGHT:
793     if (editor->selrect_active) {
794       editor_end_selection_rectangle(canvas_x, canvas_y);
795     }
796     break;
797 
798   case MOUSE_BUTTON_MIDDLE:
799     break;
800 
801   default:
802     break;
803   }
804 }
805 
806 /****************************************************************************
807   Handle a change in the size of the selection rectangle. The given point
808   is the new extremity of the rectangle.
809 ****************************************************************************/
editor_resize_selection_rectangle(int canvas_x,int canvas_y)810 static void editor_resize_selection_rectangle(int canvas_x, int canvas_y)
811 {
812   int xl, yt, xr, yb;
813 
814   if (editor->selrect_start_x <= canvas_x) {
815     xl = editor->selrect_start_x;
816     xr = canvas_x;
817   } else {
818     xl = canvas_x;
819     xr = editor->selrect_start_x;
820   }
821 
822   if (editor->selrect_start_y <= canvas_y) {
823     yt = editor->selrect_start_y;
824     yb = canvas_y;
825   } else {
826     yt = canvas_y;
827     yb = editor->selrect_start_y;
828   }
829 
830   /* Erase the previously drawn rectangle. */
831   editor_draw_selrect();
832 
833   if (xl == xr || yt == yb) {
834     editor->selrect_width = 0;
835     editor->selrect_height = 0;
836     return;
837   }
838 
839   editor->selrect_x = xl;
840   editor->selrect_y = yt;
841   editor->selrect_width = xr - xl;
842   editor->selrect_height = yb - yt;
843 
844   editor_draw_selrect();
845 }
846 
847 /****************************************************************************
848   Handle the mouse moving over the map canvas.
849 ****************************************************************************/
editor_mouse_move(int canvas_x,int canvas_y,int modifiers)850 void editor_mouse_move(int canvas_x, int canvas_y, int modifiers)
851 {
852   const struct tile *ptile, *old;
853 
854   if (!editor) {
855     return;
856   }
857 
858   old = editor_get_current_tile();
859   ptile = canvas_pos_to_tile(canvas_x, canvas_y);
860 
861   if (!ptile) {
862     return;
863   }
864 
865   if (editor->tool_active && old != NULL && old != ptile) {
866     editor_apply_tool(ptile, FALSE);
867     editor_notify_edit_finished();
868     editor_set_current_tile(ptile);
869   }
870 
871   if (editor->selrect_active) {
872     editor_resize_selection_rectangle(canvas_x, canvas_y);
873   }
874 }
875 
876 /****************************************************************************
877   Notify the server that a batch of edits has completed. This is used as
878   a hint for the server to now do any checks it has saved while the batch
879   was being processed.
880 ****************************************************************************/
editor_notify_edit_finished(void)881 void editor_notify_edit_finished(void)
882 {
883   send_packet_edit_check_tiles(&client.conn);
884 }
885 
886 /****************************************************************************
887   Apply the current editor tool to the given tile. This function is
888   suitable to called over multiple tiles at once. Once the batch of
889   operations is finished you should call editor_notify_edit_finished.
890   The 'part_of_selection' parameter should be TRUE if the tool is
891   being applied to a tile from a selection.
892 ****************************************************************************/
editor_apply_tool(const struct tile * ptile,bool part_of_selection)893 void editor_apply_tool(const struct tile *ptile,
894                        bool part_of_selection)
895 {
896   enum editor_tool_type ett;
897   enum editor_tool_mode etm;
898   int value, size, count, apno, tile, id;
899   bool erase;
900   struct connection *my_conn = &client.conn;
901 
902   if (editor == NULL || ptile == NULL) {
903     return;
904   }
905 
906   ett = editor_get_tool();
907   etm = editor_tool_get_mode(ett);
908   size = editor_tool_get_size(ett);
909   count = editor_tool_get_count(ett);
910   value = editor_tool_get_value(ett);
911   apno = editor_tool_get_applied_player(ett);
912 
913   if (ett != ETT_VISION && !client_is_global_observer()
914       && client_has_player()
915       && tile_get_known(ptile, client_player()) == TILE_UNKNOWN) {
916     return;
917   }
918 
919   if (editor_tool_has_applied_player(ett)
920       && player_by_number(apno) == NULL) {
921     return;
922   }
923 
924   if (ett == ETT_COPYPASTE) {
925     struct edit_buffer *ebuf;
926     ebuf = editor_get_copy_buffer();
927     if (etm == ETM_COPY) {
928       if (part_of_selection) {
929         edit_buffer_copy(ebuf, ptile);
930       } else {
931         edit_buffer_clear(ebuf);
932         edit_buffer_copy_square(ebuf, ptile, size);
933         editgui_refresh();
934       }
935     } else if (etm == ETM_PAINT || etm == ETM_PASTE) {
936       edit_buffer_paste(ebuf, ptile);
937     }
938     return;
939   }
940 
941   if (part_of_selection && ett != ETT_CITY) {
942     size = 1;
943   }
944 
945   erase = (etm == ETM_ERASE);
946   tile = tile_index(ptile);
947 
948   switch (ett) {
949 
950   case ETT_TERRAIN:
951     dsend_packet_edit_tile_terrain(my_conn, tile, erase ? 0 : value, size);
952     break;
953 
954   case ETT_TERRAIN_RESOURCE:
955     dsend_packet_edit_tile_resource(my_conn, tile,
956                                     erase ? resource_count() : value,
957                                     size);
958     break;
959 
960   case ETT_TERRAIN_SPECIAL:
961   case ETT_ROAD:
962   case ETT_MILITARY_BASE:
963     dsend_packet_edit_tile_extra(my_conn, tile, value, erase, size);
964     break;
965 
966   case ETT_UNIT:
967     if (erase) {
968       dsend_packet_edit_unit_remove(my_conn, apno, tile, value, count);
969     } else {
970       dsend_packet_edit_unit_create(my_conn, apno, tile, value, count, 0);
971     }
972     break;
973 
974   case ETT_CITY:
975     if (erase) {
976       struct city *pcity = tile_city(ptile);
977       if (pcity != NULL) {
978         id = pcity->id;
979         dsend_packet_edit_city_remove(my_conn, id);
980       }
981     } else {
982       dsend_packet_edit_city_create(my_conn, apno, tile, size, 0);
983     }
984     break;
985 
986   case ETT_VISION:
987     if (client_has_player()) {
988       id = client_player_number();
989       dsend_packet_edit_player_vision(my_conn, id, tile, !erase, size);
990     }
991     break;
992 
993   case ETT_STARTPOS:
994     dsend_packet_edit_startpos(my_conn, tile, erase, 0);
995     break;
996 
997   default:
998     break;
999   }
1000 }
1001 
1002 /****************************************************************************
1003   Sets the tile currently assumed to be under the user's mouse pointer.
1004 ****************************************************************************/
editor_set_current_tile(const struct tile * ptile)1005 void editor_set_current_tile(const struct tile *ptile)
1006 {
1007   if (editor == NULL) {
1008     return;
1009   }
1010 
1011   editor->current_tile = ptile;
1012 }
1013 
1014 /****************************************************************************
1015   Get the tile that the user's mouse pointer is currently over.
1016 ****************************************************************************/
editor_get_current_tile(void)1017 const struct tile *editor_get_current_tile(void)
1018 {
1019   if (editor == NULL) {
1020     return NULL;
1021   }
1022 
1023   return editor->current_tile;
1024 }
1025 
1026 /****************************************************************************
1027   Toggle the current tool mode between the given mode and ETM_PAINT (or
1028   ETM_COPY for the copy & paste tool).
1029 ****************************************************************************/
editor_tool_toggle_mode(enum editor_tool_type ett,enum editor_tool_mode etm)1030 void editor_tool_toggle_mode(enum editor_tool_type ett,
1031                              enum editor_tool_mode etm)
1032 {
1033   if (!editor_tool_has_mode(ett, etm)) {
1034     return;
1035   }
1036   if (editor_tool_get_mode(ett) == etm) {
1037     editor_tool_set_mode(ett, ett == ETT_COPYPASTE
1038                          ? ETM_COPY : ETM_PAINT);
1039   } else {
1040     editor_tool_set_mode(ett, etm);
1041   }
1042 }
1043 
1044 /****************************************************************************
1045   Set the editor tool mode to the next available mode.
1046 ****************************************************************************/
editor_tool_cycle_mode(enum editor_tool_type ett)1047 void editor_tool_cycle_mode(enum editor_tool_type ett)
1048 {
1049   int mode, count;
1050   bool found = FALSE;
1051 
1052   mode = editor_tool_get_mode(ett);
1053   if (!(0 <= mode && mode < NUM_EDITOR_TOOL_MODES)) {
1054     return;
1055   }
1056 
1057   for (count = 0; count < NUM_EDITOR_TOOL_MODES; count++) {
1058     mode = (mode + 1) % NUM_EDITOR_TOOL_MODES;
1059     if (editor_tool_has_mode(ett, mode)) {
1060       found = TRUE;
1061       break;
1062     }
1063   }
1064 
1065   if (found) {
1066     editor_tool_set_mode(ett, mode);
1067   }
1068 }
1069 
1070 /****************************************************************************
1071   Unselect all selected tiles.
1072 ****************************************************************************/
editor_selection_clear(void)1073 void editor_selection_clear(void)
1074 {
1075   if (!editor) {
1076     return;
1077   }
1078   tile_hash_clear(editor->selected_tile_table);
1079 }
1080 
1081 /****************************************************************************
1082   Add the given tile to the current selection.
1083 ****************************************************************************/
editor_selection_add(const struct tile * ptile)1084 void editor_selection_add(const struct tile *ptile)
1085 {
1086   if (!editor || !ptile) {
1087     return;
1088   }
1089   tile_hash_insert(editor->selected_tile_table, ptile, NULL);
1090 }
1091 
1092 /****************************************************************************
1093   Remove the given tile from the current selection.
1094 ****************************************************************************/
editor_selection_remove(const struct tile * ptile)1095 void editor_selection_remove(const struct tile *ptile)
1096 {
1097   if (!editor || !ptile) {
1098     return;
1099   }
1100   tile_hash_remove(editor->selected_tile_table, ptile);
1101 }
1102 
1103 /****************************************************************************
1104   Returns TRUE if the given tile is selected.
1105 ****************************************************************************/
editor_tile_is_selected(const struct tile * ptile)1106 bool editor_tile_is_selected(const struct tile *ptile)
1107 {
1108   if (!editor || !ptile) {
1109     return FALSE;
1110   }
1111   return tile_hash_lookup(editor->selected_tile_table, ptile, NULL);
1112 }
1113 
1114 /****************************************************************************
1115   Apply the current editor tool to all tiles in the current selection.
1116 ****************************************************************************/
editor_apply_tool_to_selection(void)1117 void editor_apply_tool_to_selection(void)
1118 {
1119   enum editor_tool_type ett;
1120 
1121   if (!editor || editor_selection_count() <= 0) {
1122     return;
1123   }
1124 
1125   ett = editor_get_tool();
1126   if (editor_tool_get_mode(ett) == ETM_COPY) {
1127     struct edit_buffer *ebuf;
1128     ebuf = editor_get_copy_buffer();
1129     edit_buffer_clear(ebuf);
1130     edit_buffer_set_origin(ebuf, editor_get_selection_center());
1131   }
1132 
1133   connection_do_buffer(&client.conn);
1134   tile_hash_iterate(editor->selected_tile_table, ptile) {
1135     editor_apply_tool(ptile, TRUE);
1136   } tile_hash_iterate_end;
1137   editor_notify_edit_finished();
1138   connection_do_unbuffer(&client.conn);
1139 
1140   if (editor_tool_get_mode(ett) == ETM_COPY) {
1141     editgui_refresh();
1142   }
1143 }
1144 
1145 /****************************************************************************
1146   Get the translated name of the given tool type.
1147 ****************************************************************************/
editor_tool_get_name(enum editor_tool_type ett)1148 const char *editor_tool_get_name(enum editor_tool_type ett)
1149 {
1150   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1151     return "";
1152   }
1153 
1154   return editor->tools[ett].name;
1155 }
1156 
1157 /****************************************************************************
1158   Get the translated name of the given tool value. If no such name exists,
1159   returns an empty string.
1160 ****************************************************************************/
editor_tool_get_value_name(enum editor_tool_type emt,int value)1161 const char *editor_tool_get_value_name(enum editor_tool_type emt, int value)
1162 {
1163   struct terrain *pterrain;
1164   struct resource *presource;
1165   struct unit_type *putype;
1166   struct extra_type *pextra;
1167 
1168   if (!editor) {
1169     return "";
1170   }
1171 
1172   switch (emt) {
1173   case ETT_TERRAIN:
1174     pterrain = terrain_by_number(value);
1175     return pterrain ? terrain_name_translation(pterrain) : "";
1176     break;
1177   case ETT_TERRAIN_RESOURCE:
1178     presource = resource_by_number(value);
1179     return presource ? resource_name_translation(presource) : "";
1180     break;
1181   case ETT_TERRAIN_SPECIAL:
1182   case ETT_ROAD:
1183   case ETT_MILITARY_BASE:
1184     pextra = extra_by_number(value);
1185     return pextra != NULL ? extra_name_translation(pextra) : "";
1186     break;
1187   case ETT_UNIT:
1188     putype = utype_by_number(value);
1189     return putype ? utype_name_translation(putype) : "";
1190     break;
1191   default:
1192     break;
1193   }
1194   return "";
1195 }
1196 
1197 /****************************************************************************
1198   Return TRUE if the given editor tool uses the 'size' parameter.
1199 ****************************************************************************/
editor_tool_has_size(enum editor_tool_type ett)1200 bool editor_tool_has_size(enum editor_tool_type ett)
1201 {
1202   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1203     return FALSE;
1204   }
1205   return editor->tools[ett].flags & ETF_HAS_SIZE;
1206 }
1207 
1208 /****************************************************************************
1209   Returns the current size parameter for the given editor tools.
1210 ****************************************************************************/
editor_tool_get_size(enum editor_tool_type ett)1211 int editor_tool_get_size(enum editor_tool_type ett)
1212 {
1213   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1214     return 1;
1215   }
1216   return editor->tools[ett].size;
1217 }
1218 
1219 /****************************************************************************
1220   Sets the size parameter for the given tool.
1221 ****************************************************************************/
editor_tool_set_size(enum editor_tool_type ett,int size)1222 void editor_tool_set_size(enum editor_tool_type ett, int size)
1223 {
1224   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1225     return;
1226   }
1227   editor->tools[ett].size = MAX(1, size);
1228 }
1229 
1230 /****************************************************************************
1231   Return TRUE if it is meaningful for the given tool to use the 'count'
1232   parameter.
1233 ****************************************************************************/
editor_tool_has_count(enum editor_tool_type ett)1234 bool editor_tool_has_count(enum editor_tool_type ett)
1235 {
1236   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1237     return FALSE;
1238   }
1239   return editor->tools[ett].flags & ETF_HAS_COUNT;
1240 }
1241 
1242 /****************************************************************************
1243   Returns the 'count' parameter for the editor tool.
1244 ****************************************************************************/
editor_tool_get_count(enum editor_tool_type ett)1245 int editor_tool_get_count(enum editor_tool_type ett)
1246 {
1247   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1248     return 1;
1249   }
1250   return editor->tools[ett].count;
1251 }
1252 
1253 /****************************************************************************
1254   Sets the 'count' parameter of the tool to the given value.
1255 ****************************************************************************/
editor_tool_set_count(enum editor_tool_type ett,int count)1256 void editor_tool_set_count(enum editor_tool_type ett, int count)
1257 {
1258   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1259     return;
1260   }
1261   editor->tools[ett].count = MAX(1, count);
1262 }
1263 
1264 /****************************************************************************
1265   Returns a sprite containing an icon for the given tool type. Returns
1266   NULL if no such sprite exists.
1267 ****************************************************************************/
editor_tool_get_sprite(enum editor_tool_type ett)1268 struct sprite *editor_tool_get_sprite(enum editor_tool_type ett)
1269 {
1270   const struct editor_sprites *sprites;
1271 
1272   if (!tileset || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1273     return NULL;
1274   }
1275 
1276   sprites = get_editor_sprites(tileset);
1277   if (!sprites) {
1278     return NULL;
1279   }
1280 
1281   switch (ett) {
1282   case ETT_COPYPASTE:
1283     return sprites->copypaste;
1284     break;
1285   case ETT_TERRAIN:
1286     return sprites->terrain;
1287     break;
1288   case ETT_TERRAIN_RESOURCE:
1289     return sprites->terrain_resource;
1290     break;
1291   case ETT_TERRAIN_SPECIAL:
1292     return sprites->terrain_special;
1293     break;
1294   case ETT_ROAD:
1295     return sprites->road;
1296   case ETT_MILITARY_BASE:
1297     return sprites->military_base;
1298   case ETT_UNIT:
1299     return sprites->unit;
1300     break;
1301   case ETT_CITY:
1302     return sprites->city;
1303     break;
1304   case ETT_VISION:
1305     return sprites->vision;
1306     break;
1307   case ETT_STARTPOS:
1308     return sprites->startpos;
1309     break;
1310   default:
1311     break;
1312   }
1313 
1314   return NULL;
1315 }
1316 
1317 /****************************************************************************
1318   Returns a translated "tooltip" description for the given tool type.
1319 ****************************************************************************/
editor_tool_get_tooltip(enum editor_tool_type ett)1320 const char *editor_tool_get_tooltip(enum editor_tool_type ett)
1321 {
1322   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)
1323       || !editor->tools[ett].tooltip) {
1324     return "";
1325   }
1326   return editor->tools[ett].tooltip;
1327 }
1328 
1329 /****************************************************************************
1330   Returns the current applied player number for the editor tool.
1331 
1332   May return a player number for which player_by_number returns NULL.
1333 ****************************************************************************/
editor_tool_get_applied_player(enum editor_tool_type ett)1334 int editor_tool_get_applied_player(enum editor_tool_type ett)
1335 {
1336   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1337     return -1;
1338   }
1339   return editor->tools[ett].applied_player_no;
1340 }
1341 
1342 /****************************************************************************
1343   Sets the editor tool's applied player number to the given value.
1344 ****************************************************************************/
editor_tool_set_applied_player(enum editor_tool_type ett,int player_no)1345 void editor_tool_set_applied_player(enum editor_tool_type ett,
1346                                     int player_no)
1347 {
1348   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1349     return;
1350   }
1351   editor->tools[ett].applied_player_no = player_no;
1352 }
1353 
1354 /****************************************************************************
1355   Returns TRUE if the given tool makes use of the editor's applied player
1356   number.
1357 ****************************************************************************/
editor_tool_has_applied_player(enum editor_tool_type ett)1358 bool editor_tool_has_applied_player(enum editor_tool_type ett)
1359 {
1360   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1361     return FALSE;
1362   }
1363   return editor->tools[ett].flags & ETF_HAS_APPLIED_PLAYER;
1364 }
1365 
1366 /****************************************************************************
1367   Returns TRUE if erase mode for the given tool erases by sub-value instead
1368   of any object corresponding to the tool type.
1369 ****************************************************************************/
editor_tool_has_value_erase(enum editor_tool_type ett)1370 bool editor_tool_has_value_erase(enum editor_tool_type ett)
1371 {
1372   if (!editor || !(0 <= ett && ett < NUM_EDITOR_TOOL_TYPES)) {
1373     return FALSE;
1374   }
1375   return editor->tools[ett].flags & ETF_HAS_VALUE_ERASE;
1376 }
1377 
1378 /****************************************************************************
1379   Returns the number of currently selected tiles.
1380 ****************************************************************************/
editor_selection_count(void)1381 int editor_selection_count(void)
1382 {
1383   if (!editor) {
1384     return 0;
1385   }
1386   return tile_hash_size(editor->selected_tile_table);
1387 }
1388 
1389 /****************************************************************************
1390   Creates a virtual unit (like unit_virtual_create) based on the current
1391   editor state. You should free() the unit when it is no longer needed.
1392   If creation is not possible, then NULL is returned.
1393 
1394   The virtual unit has no homecity or tile. It is owned by the player
1395   corresponding to the current 'applied player' parameter and has unit type
1396   given by the sub-value of the unit tool (ETT_UNIT).
1397 ****************************************************************************/
editor_unit_virtual_create(void)1398 struct unit *editor_unit_virtual_create(void)
1399 {
1400   struct unit *vunit;
1401   struct player *pplayer;
1402   struct unit_type *putype;
1403   int apno, value;
1404 
1405   value = editor_tool_get_value(ETT_UNIT);
1406   putype = utype_by_number(value);
1407 
1408   if (!putype) {
1409     return NULL;
1410   }
1411 
1412   apno = editor_tool_get_applied_player(ETT_UNIT);
1413   pplayer = player_by_number(apno);
1414   if (!pplayer) {
1415     return NULL;
1416   }
1417 
1418   vunit = unit_virtual_create(pplayer, NULL, putype, 0);
1419 
1420   return vunit;
1421 }
1422 
1423 /****************************************************************************
1424   Create a new edit buffer corresponding to all types set in 'type_flags'.
1425 ****************************************************************************/
edit_buffer_new(int type_flags)1426 struct edit_buffer *edit_buffer_new(int type_flags)
1427 {
1428   struct edit_buffer *ebuf;
1429 
1430   if (!(0 <= type_flags && type_flags <= EBT_ALL)) {
1431     return NULL;
1432   }
1433 
1434   ebuf = fc_calloc(1, sizeof(*ebuf));
1435   ebuf->type_flags = type_flags;
1436   ebuf->vtiles = tile_list_new();
1437 
1438   return ebuf;
1439 }
1440 
1441 /****************************************************************************
1442   Free all memory allocated for the edit buffer.
1443 ****************************************************************************/
edit_buffer_free(struct edit_buffer * ebuf)1444 void edit_buffer_free(struct edit_buffer *ebuf)
1445 {
1446   if (!ebuf) {
1447     return;
1448   }
1449 
1450   if (ebuf->vtiles) {
1451     tile_list_iterate(ebuf->vtiles, vtile) {
1452       tile_virtual_destroy(vtile);
1453     } tile_list_iterate_end;
1454     tile_list_destroy(ebuf->vtiles);
1455     ebuf->vtiles = NULL;
1456   }
1457   free(ebuf);
1458 }
1459 
1460 /****************************************************************************
1461   Remove all copy data stored in the edit buffer.
1462 ****************************************************************************/
edit_buffer_clear(struct edit_buffer * ebuf)1463 void edit_buffer_clear(struct edit_buffer *ebuf)
1464 {
1465   if (!ebuf || !ebuf->vtiles) {
1466     return;
1467   }
1468 
1469   tile_list_iterate(ebuf->vtiles, vtile) {
1470     tile_virtual_destroy(vtile);
1471   } tile_list_iterate_end;
1472   tile_list_clear(ebuf->vtiles);
1473 
1474   edit_buffer_set_origin(ebuf, NULL);
1475 }
1476 
1477 /****************************************************************************
1478   Copy from a square region of half-width 'radius' centered around 'center'
1479   into the buffer.
1480 ****************************************************************************/
edit_buffer_copy_square(struct edit_buffer * ebuf,const struct tile * center,int radius)1481 void edit_buffer_copy_square(struct edit_buffer *ebuf,
1482                              const struct tile *center,
1483                              int radius)
1484 {
1485   if (!ebuf || !center || radius < 1) {
1486     return;
1487   }
1488 
1489   edit_buffer_set_origin(ebuf, center);
1490   square_iterate(center, radius - 1, ptile) {
1491     edit_buffer_copy(ebuf, ptile);
1492   } square_iterate_end;
1493 }
1494 
1495 /****************************************************************************
1496   Append a single tile to the copy buffer.
1497 ****************************************************************************/
edit_buffer_copy(struct edit_buffer * ebuf,const struct tile * ptile)1498 void edit_buffer_copy(struct edit_buffer *ebuf, const struct tile *ptile)
1499 {
1500   struct tile *vtile;
1501   struct unit *vunit;
1502   bool copied = FALSE;
1503 
1504   if (!ebuf || !ptile) {
1505     return;
1506   }
1507 
1508   vtile = tile_virtual_new(NULL);
1509   vtile->index = tile_index(ptile);
1510 
1511   edit_buffer_type_iterate(ebuf, type) {
1512     switch (type) {
1513     case EBT_TERRAIN:
1514       if (tile_terrain(ptile)) {
1515         tile_set_terrain(vtile, tile_terrain(ptile));
1516         copied = TRUE;
1517       }
1518       break;
1519     case EBT_RESOURCE:
1520       if (tile_resource(ptile)) {
1521         tile_set_resource(vtile, tile_resource(ptile));
1522         copied = TRUE;
1523       }
1524       break;
1525     case EBT_SPECIAL:
1526       extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
1527         if (tile_has_extra(ptile, pextra)) {
1528           tile_add_extra(vtile, pextra);
1529           copied = TRUE;
1530         }
1531       } extra_type_by_cause_iterate_end;
1532       break;
1533     case EBT_BASE:
1534       extra_type_iterate(pextra) {
1535         if (tile_has_extra(ptile, pextra)
1536             && is_extra_caused_by(pextra, EC_BASE)) {
1537           tile_add_extra(vtile, pextra);
1538           copied = TRUE;
1539         }
1540       } extra_type_iterate_end;
1541       break;
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;
1548         }
1549       } extra_type_iterate_end;
1550       break;
1551     case EBT_UNIT:
1552       unit_list_iterate(ptile->units, punit) {
1553         if (!punit) {
1554           continue;
1555         }
1556         vunit = unit_virtual_create(unit_owner(punit), NULL,
1557                                     unit_type_get(punit), punit->veteran);
1558         vunit->homecity = punit->homecity;
1559         vunit->hp = punit->hp;
1560         unit_list_append(vtile->units, vunit);
1561         copied = TRUE;
1562       } unit_list_iterate_end;
1563       break;
1564     case EBT_CITY:
1565       if (tile_city(ptile)) {
1566         struct city *pcity, *vcity;
1567         char name[MAX_LEN_NAME];
1568 
1569         pcity = tile_city(ptile);
1570         fc_snprintf(name, sizeof(name), "Copy of %s",
1571                     city_name_get(pcity));
1572         vcity = create_city_virtual(city_owner(pcity), NULL, name);
1573         city_size_set(vcity, city_size_get(pcity));
1574         improvement_iterate(pimprove) {
1575           if (!is_improvement(pimprove)
1576               || !city_has_building(pcity, pimprove)) {
1577             continue;
1578           }
1579           city_add_improvement(vcity, pimprove);
1580         } improvement_iterate_end;
1581         tile_set_worked(vtile, vcity);
1582         copied = TRUE;
1583       }
1584       break;
1585     default:
1586       break;
1587     }
1588   } edit_buffer_type_iterate_end;
1589 
1590   if (copied) {
1591     tile_list_append(ebuf->vtiles, vtile);
1592   } else {
1593     tile_virtual_destroy(vtile);
1594   }
1595 }
1596 
1597 /****************************************************************************
1598   Helper function to fill in an edit packet with the tile's current values.
1599 ****************************************************************************/
fill_tile_edit_packet(struct packet_edit_tile * packet,const struct tile * ptile)1600 static void fill_tile_edit_packet(struct packet_edit_tile *packet,
1601                                   const struct tile *ptile)
1602 {
1603   const struct resource *presource;
1604   const struct terrain *pterrain;
1605 
1606   if (!packet || !ptile) {
1607     return;
1608   }
1609   packet->tile = tile_index(ptile);
1610   packet->extras = *tile_extras(ptile);
1611 
1612   presource = tile_resource(ptile);
1613   packet->resource = presource
1614                      ? resource_number(presource)
1615                      : resource_count();
1616 
1617   pterrain = tile_terrain(ptile);
1618   packet->terrain = pterrain
1619                     ? terrain_number(pterrain)
1620                     : terrain_count();
1621 
1622   if (ptile->label == NULL) {
1623     packet->label[0] = '\0';
1624   } else {
1625     sz_strlcpy(packet->label, ptile->label);
1626   }
1627 }
1628 
1629 /****************************************************************************
1630   Helper function for edit_buffer_paste(). Do a single paste of the stuff set
1631   in the buffer on the virtual tile to the destination tile 'ptile_dest'.
1632 ****************************************************************************/
paste_tile(struct edit_buffer * ebuf,const struct tile * vtile,const struct tile * ptile_dest)1633 static void paste_tile(struct edit_buffer *ebuf,
1634                        const struct tile *vtile,
1635                        const struct tile *ptile_dest)
1636 {
1637   struct connection *my_conn = &client.conn;
1638   struct packet_edit_tile tile_packet;
1639   struct city *vcity;
1640   int value, owner, tile;
1641   bool send_edit_tile = FALSE;
1642 
1643   if (!ebuf || !vtile || !ptile_dest) {
1644     return;
1645   }
1646 
1647   tile = tile_index(ptile_dest);
1648 
1649   fill_tile_edit_packet(&tile_packet, ptile_dest);
1650 
1651   edit_buffer_type_iterate(ebuf, type) {
1652     switch (type) {
1653     case EBT_TERRAIN:
1654       if (!tile_terrain(vtile)) {
1655         continue;
1656       }
1657       value = terrain_number(tile_terrain(vtile));
1658       dsend_packet_edit_tile_terrain(my_conn, tile, value, 1);
1659       break;
1660     case EBT_RESOURCE:
1661       if (!tile_resource(vtile)) {
1662         continue;
1663       }
1664       value = resource_number(tile_resource(vtile));
1665       dsend_packet_edit_tile_resource(my_conn, tile, value, 1);
1666       break;
1667     case EBT_SPECIAL:
1668       extra_type_by_cause_iterate(EC_SPECIAL, pextra) {
1669         if (tile_has_extra(vtile, pextra)) {
1670           BV_SET(tile_packet.extras, extra_index(pextra));
1671           send_edit_tile = TRUE;
1672         }
1673       } extra_type_by_cause_iterate_end;
1674       break;
1675     case EBT_BASE:
1676       extra_type_iterate(pextra) {
1677         if (tile_has_extra(vtile, pextra)
1678             && is_extra_caused_by(pextra, EC_BASE)) {
1679           BV_SET(tile_packet.extras, extra_index(pextra));
1680           send_edit_tile = TRUE;
1681         }
1682       } extra_type_iterate_end;
1683       break;
1684     case EBT_ROAD:
1685       extra_type_iterate(pextra) {
1686         if (tile_has_extra(vtile, pextra)
1687             && is_extra_caused_by(pextra, EC_ROAD)) {
1688           BV_SET(tile_packet.extras, extra_index(pextra));
1689           send_edit_tile = TRUE;
1690         }
1691       } extra_type_iterate_end;
1692       break;
1693     case EBT_UNIT:
1694       unit_list_iterate(vtile->units, vunit) {
1695         value = utype_number(unit_type_get(vunit));
1696         owner = player_number(unit_owner(vunit));
1697         dsend_packet_edit_unit_create(my_conn, owner, tile, value, 1, 0);
1698       } unit_list_iterate_end;
1699       break;
1700     case EBT_CITY:
1701       vcity = tile_city(vtile);
1702       if (!vcity) {
1703         continue;
1704       }
1705       owner = player_number(city_owner(vcity));
1706       value = city_size_get(vcity);
1707       dsend_packet_edit_city_create(my_conn, owner, tile, value, 0);
1708       break;
1709     default:
1710       break;
1711     }
1712   } edit_buffer_type_iterate_end;
1713 
1714   if (send_edit_tile) {
1715     send_packet_edit_tile(my_conn, &tile_packet);
1716   }
1717 }
1718 
1719 /****************************************************************************
1720   Paste the entire contents of the edit buffer using 'dest' as the origin.
1721 ****************************************************************************/
edit_buffer_paste(struct edit_buffer * ebuf,const struct tile * dest)1722 void edit_buffer_paste(struct edit_buffer *ebuf, const struct tile *dest)
1723 {
1724   struct connection *my_conn = &client.conn;
1725   const struct tile *origin, *ptile;
1726   int dx, dy;
1727 
1728   if (!ebuf || !dest) {
1729     return;
1730   }
1731 
1732   /* Calculate vector. */
1733   origin = edit_buffer_get_origin(ebuf);
1734   fc_assert_ret(origin != NULL);
1735   map_distance_vector(&dx, &dy, origin, dest);
1736 
1737   connection_do_buffer(my_conn);
1738   tile_list_iterate(ebuf->vtiles, vtile) {
1739     int virt_x, virt_y;
1740 
1741     index_to_map_pos(&virt_x, &virt_y, tile_index(vtile));
1742     ptile = map_pos_to_tile(virt_x + dx, virt_y + dy);
1743     if (!ptile) {
1744       continue;
1745     }
1746     paste_tile(ebuf, vtile, ptile);
1747   } tile_list_iterate_end;
1748   connection_do_unbuffer(my_conn);
1749 }
1750 
1751 /****************************************************************************
1752   Returns the copy buffer for the given tool.
1753 ****************************************************************************/
editor_get_copy_buffer(void)1754 struct edit_buffer *editor_get_copy_buffer(void)
1755 {
1756   if (!editor) {
1757     return NULL;
1758   }
1759   return editor->copybuf;
1760 }
1761 
1762 /****************************************************************************
1763   Returns the translated string name for the given mode.
1764 ****************************************************************************/
editor_tool_get_mode_name(enum editor_tool_type ett,enum editor_tool_mode etm)1765 const char *editor_tool_get_mode_name(enum editor_tool_type ett,
1766                                       enum editor_tool_mode etm)
1767 {
1768   bool value_erase;
1769 
1770   value_erase = editor_tool_has_value_erase(ett);
1771 
1772   switch (etm) {
1773   case ETM_PAINT:
1774     return _("Paint");
1775     break;
1776   case ETM_ERASE:
1777     if (value_erase) {
1778       return _("Erase Value");
1779     } else {
1780       return _("Erase");
1781     }
1782     break;
1783   case ETM_COPY:
1784     return _("Copy");
1785     break;
1786   case ETM_PASTE:
1787     return _("Paste");
1788     break;
1789   default:
1790     log_error("Unrecognized editor tool mode %d "
1791               "in editor_tool_get_mode_name().", etm);
1792     break;
1793   }
1794 
1795   return "";
1796 }
1797 
1798 /****************************************************************************
1799   Returns a translated tooltip string assumed to be used for the toggle
1800   button for this tool mode in the editor gui.
1801 ****************************************************************************/
editor_get_mode_tooltip(enum editor_tool_mode etm)1802 const char *editor_get_mode_tooltip(enum editor_tool_mode etm)
1803 {
1804   switch (etm) {
1805   case ETM_ERASE:
1806     return _("Toggle erase mode.\nShortcut: shift-d");
1807     break;
1808   case ETM_COPY:
1809     return _("Toggle copy mode.\nShortcut: shift-c");
1810     break;
1811   case ETM_PASTE:
1812     return _("Toggle paste mode.\nShortcut: shift-v");
1813     break;
1814   default:
1815     break;
1816   }
1817 
1818   return NULL;
1819 }
1820 
1821 /****************************************************************************
1822   Returns the editor sprite corresponding to the tool mode.
1823 ****************************************************************************/
editor_get_mode_sprite(enum editor_tool_mode etm)1824 struct sprite *editor_get_mode_sprite(enum editor_tool_mode etm)
1825 {
1826   const struct editor_sprites *sprites;
1827 
1828   sprites = get_editor_sprites(tileset);
1829   if (!sprites) {
1830     return NULL;
1831   }
1832 
1833   switch (etm) {
1834   case ETM_PAINT:
1835     return sprites->brush;
1836     break;
1837   case ETM_ERASE:
1838     return sprites->erase;
1839     break;
1840   case ETM_COPY:
1841     return sprites->copy;
1842     break;
1843   case ETM_PASTE:
1844     return sprites->paste;
1845     break;
1846   default:
1847     break;
1848   }
1849 
1850   return NULL;
1851 }
1852 
1853 /****************************************************************************
1854   Fill the supplied buffer with a translated string describing the edit
1855   buffer's current state. Returns the number of bytes used.
1856 ****************************************************************************/
edit_buffer_get_status_string(const struct edit_buffer * ebuf,char * buf,int buflen)1857 int edit_buffer_get_status_string(const struct edit_buffer *ebuf,
1858                                   char *buf, int buflen)
1859 {
1860   int ret, total;
1861   const char *fmt;
1862 
1863   if (!buf || buflen < 1) {
1864     return 0;
1865   }
1866 
1867   ret = fc_strlcpy(buf, _("Buffer empty."), buflen);
1868   if (!ebuf || !ebuf->vtiles) {
1869     return ret;
1870   }
1871 
1872   total = tile_list_size(ebuf->vtiles);
1873   if (total > 0) {
1874     fmt = PL_("%d tile copied.", "%d tiles copied.", total);
1875     ret = fc_snprintf(buf, buflen, fmt, total);
1876   }
1877 
1878   return ret;
1879 }
1880 
1881 /****************************************************************************
1882   Set the "origin" for subsequent copy operations. This controls the x and
1883   y offset of newly created virtual tiles in the buffer.
1884 ****************************************************************************/
edit_buffer_set_origin(struct edit_buffer * ebuf,const struct tile * ptile)1885 void edit_buffer_set_origin(struct edit_buffer *ebuf,
1886                             const struct tile *ptile)
1887 {
1888   if (!ebuf) {
1889     return;
1890   }
1891   ebuf->origin = ptile;
1892 }
1893 
1894 /****************************************************************************
1895   Return the previously set origin, or NULL if none.
1896 ****************************************************************************/
edit_buffer_get_origin(const struct edit_buffer * ebuf)1897 const struct tile *edit_buffer_get_origin(const struct edit_buffer *ebuf)
1898 {
1899   if (!ebuf) {
1900     return NULL;
1901   }
1902   return ebuf->origin;
1903 }
1904 
1905 /****************************************************************************
1906   Returns TRUE if the edit buffer was created with the given type flag.
1907 ****************************************************************************/
edit_buffer_has_type(const struct edit_buffer * ebuf,int type)1908 bool edit_buffer_has_type(const struct edit_buffer *ebuf, int type)
1909 {
1910   if (!ebuf) {
1911     return FALSE;
1912   }
1913   return ebuf->type_flags & type;
1914 }
1915 
1916 /****************************************************************************
1917   Returns the "center" tile of a group of selected tiles, or NULL.
1918   The center is calculated as the vector sum divided by the number of tiles,
1919   i.e. the average of the map distance vectors of the selected tiles.
1920 ****************************************************************************/
editor_get_selection_center(void)1921 const struct tile *editor_get_selection_center(void)
1922 {
1923   int count;
1924   const struct tile *origin, *center;
1925   int dx, dy, cx, cy;
1926   int xsum = 0, ysum = 0;
1927 
1928   if (!editor || !editor->selected_tile_table) {
1929     return NULL;
1930   }
1931 
1932   count = tile_hash_size(editor->selected_tile_table);
1933   if (count < 1) {
1934     return NULL;
1935   }
1936 
1937   origin = map_pos_to_tile(0, 0);
1938   tile_hash_iterate(editor->selected_tile_table, ptile) {
1939     map_distance_vector(&dx, &dy, origin, ptile);
1940     xsum += dx;
1941     ysum += dy;
1942   } tile_hash_iterate_end;
1943 
1944   cx = xsum / count;
1945   cy = ysum / count;
1946   center = map_pos_to_tile(cx, cy);
1947 
1948   return center;
1949 }
1950