1 /*
2  * Copyright (c) 2008 prissi
3  *
4  * This file is part of the Simutrans project under the artistic license.
5  *
6  * New configurable OOP tool system
7  */
8 
9 #ifndef simmenu_h
10 #define simmenu_h
11 
12 #include <string>
13 #include "descriptor/sound_desc.h"
14 
15 #include "dataobj/koord3d.h"
16 #include "dataobj/translator.h"
17 
18 #include "simtypes.h"
19 #include "display/simimg.h"
20 
21 
22 template<class T> class vector_tpl;
23 template<class T> class slist_tpl;
24 
25 class scr_coord;
26 class tool_selector_t;
27 class player_t;
28 class toolbar_t;
29 class memory_rw_t;
30 class karte_ptr_t;
31 class zeiger_t;
32 
33 enum {
34 	// general tools
35 	TOOL_QUERY=0,
36 	TOOL_REMOVER,
37 	TOOL_RAISE_LAND,
38 	TOOL_LOWER_LAND,
39 	TOOL_SETSLOPE,
40 	TOOL_RESTORESLOPE,
41 	TOOL_MARKER,
42 	TOOL_CLEAR_RESERVATION,
43 	TOOL_TRANSFORMER,
44 	TOOL_ADD_CITY,
45 	TOOL_CHANGE_CITY_SIZE,
46 	TOOL_PLANT_TREE,
47 	TOOL_SCHEDULE_ADD,
48 	TOOL_SCHEDULE_INS,
49 	TOOL_BUILD_WAY,
50 	TOOL_BUILD_BRIDGE,
51 	TOOL_BUILD_TUNNEL,
52 	TOOL_WAYREMOVER,
53 	TOOL_BUILD_WAYOBJ,
54 	TOOL_BUILD_STATION,
55 	TOOL_BUILD_ROADSIGN,
56 	TOOL_BUILD_DEPOT,
57 	TOOL_BUILD_HOUSE,
58 	TOOL_BUILD_LAND_CHAIN,
59 	TOOL_CITY_CHAIN,
60 	TOOL_BUILD_FACTORY,
61 	TOOL_LINK_FACTORY,
62 	TOOL_HEADQUARTER,
63 	TOOL_LOCK_GAME,
64 	TOOL_ADD_CITYCAR,
65 	TOOL_FOREST,
66 	TOOL_STOP_MOVER,
67 	TOOL_MAKE_STOP_PUBLIC,
68 	TOOL_REMOVE_WAYOBJ,
69 	TOOL_SLICED_AND_UNDERGROUND_VIEW,
70 	TOOL_BUY_HOUSE,
71 	TOOL_BUILD_CITYROAD,
72 	TOOL_ERROR_MESSAGE,
73 	TOOL_CHANGE_WATER_HEIGHT,
74 	TOOL_SET_CLIMATE,
75 	TOOL_ROTATE_BUILDING,
76 	TOOL_MERGE_STOP,
77 	GENERAL_TOOL_COUNT,
78 	GENERAL_TOOL = 0x1000
79 };
80 
81 enum {
82 	// simple one click tools
83 	TOOL_PAUSE = 0,
84 	TOOL_FASTFORWARD,
85 	TOOL_SCREENSHOT,
86 	TOOL_INCREASE_INDUSTRY,
87 	TOOL_UNDO,
88 	TOOL_SWITCH_PLAYER,
89 	TOOL_STEP_YEAR,
90 	TOOL_CHANGE_GAME_SPEED,
91 	TOOL_ZOOM_IN,
92 	TOOL_ZOOM_OUT,
93 	TOOL_SHOW_COVERAGE,
94 	TOOL_SHOW_NAME,
95 	TOOL_SHOW_GRID,
96 	TOOL_SHOW_TREES,
97 	TOOL_SHOW_HOUSES,
98 	TOOL_SHOW_UNDERGROUND,
99 	TOOL_ROTATE90,
100 	TOOL_QUIT,
101 	TOOL_FILL_TREES,
102 	TOOL_DAYNIGHT_LEVEL,
103 	TOOL_VEHICLE_TOOLTIPS,
104 	TOOL_TOOGLE_PAX,
105 	TOOL_TOOGLE_PEDESTRIANS,
106 	TOOL_TRAFFIC_LEVEL,
107 	TOOL_CHANGE_CONVOI,
108 	TOOL_CHANGE_LINE,
109 	TOOL_CHANGE_DEPOT,
110 	UNUSED_WKZ_PWDHASH_TOOL,
111 	TOOL_CHANGE_PLAYER,
112 	TOOL_CHANGE_TRAFFIC_LIGHT,
113 	TOOL_CHANGE_CITY,
114 	TOOL_RENAME,
115 	TOOL_ADD_MESSAGE,
116 	TOOL_TOGGLE_RESERVATION,
117 	TOOL_VIEW_OWNER,
118 	TOOL_HIDE_UNDER_CURSOR,
119 	SIMPLE_TOOL_COUNT,
120 	SIMPLE_TOOL = 0x2000
121 };
122 
123 enum {
124 	// dialogue tools
125 	DIALOG_HELP = 0,
126 	DIALOG_OPTIONS,
127 	DIALOG_MINIMAP,
128 	DIALOG_LINEOVERVIEW,
129 	DIALOG_MESSAGES,
130 	DIALOG_FINANCES,
131 	DIALOG_PLAYERS,
132 	DIALOG_DISPLAYOPTIONS,
133 	DIALOG_SOUND,
134 	DIALOG_LANGUAGE,
135 	DIALOG_PLAYERCOLOR,
136 	DIALOG_JUMP,
137 	DIALOG_LOAD,
138 	DIALOG_SAVE,
139 	DIALOG_LIST_HALT,
140 	DIALOG_LIST_CONVOI,
141 	DIALOG_LIST_TOWN,
142 	DIALOG_LIST_GOODS,
143 	DIALOG_LIST_FACTORY,
144 	DIALOG_LIST_CURIOSITY,
145 	DIALOG_EDIT_FACTORY,
146 	DIALOG_EDIT_ATTRACTION,
147 	DIALOG_EDIT_HOUSE,
148 	DIALOG_EDIT_TREE,
149 	DIALOG_ENLARGE_MAP,
150 	DIALOG_LIST_LABEL,
151 	DIALOG_CLIMATES,
152 	DIALOG_SETTINGS,
153 	DIALOG_GAMEINFO,
154 	DIALOG_THEMES,
155 	DIALOG_SCENARIO,
156 	DIALOG_SCENARIO_INFO,
157 	DIALOGE_TOOL_COUNT,
158 	DIALOGE_TOOL = 0x4000
159 };
160 
161 enum {
162 	// toolbars
163 	TOOL_MAINMENU = 0,
164 	TOOL_LAST_USED = 1022,
165 	TOOLBAR_TOOL = 0x8000u
166 };
167 
168 class tool_t {
169 protected:
170 	image_id icon;
171 private:
172 	/* value to trigger this command (see documentation) */
173 	uint16 id;
174 
175 protected:
176 	static karte_ptr_t welt;
177 
178 	const char *default_param;
179 public:
get_id()180 	uint16 get_id() const { return id; }
181 
182 	static tool_t *dummy;
183 
184 	// for key lookup
185 	static vector_tpl<tool_t *>char_to_tool;
186 
187 	/// cursor image
188 	image_id cursor;
189 
190 	/// cursor marks this area
191 	koord cursor_area;
192 
193 	/// cursor centered at marked area? default: false
194 	bool cursor_centered;
195 
196 	/// cursor offset within marked area (only effective if cursor_centered != false)
197 	koord cursor_offset;
198 
199 	/// z-offset of cursor, possible values: Z_PLAN and Z_GRID
200 	sint8 offset;
201 
202 	sint16 ok_sound;
203 
204 	/// a script is waiting for a call-back
205 	uint32 callback_id;
206 
207 	enum {
208 		WFL_SHIFT  = 1, ///< shift-key was pressed when mouse-click happened
209 		WFL_CTRL   = 2, ///< ctrl-key was pressed when mouse-click happened
210 		WFL_LOCAL  = 4, ///< tool call was issued by local client
211 		WFL_SCRIPT = 8, ///< tool call was issued by script
212 		WFL_NO_CHK = 16, ///< tool call needs no password or scenario checks
213 	};
214 	uint8 flags; // flags are set before init/work/move is called
215 
is_ctrl_pressed()216 	bool is_ctrl_pressed()    const { return flags & WFL_CTRL; }
is_shift_pressed()217 	bool is_shift_pressed()   const { return flags & WFL_SHIFT; }
is_local_execution()218 	bool is_local_execution() const { return flags & WFL_LOCAL; }
is_scripted()219 	bool is_scripted()        const { return flags & WFL_SCRIPT; }
no_check()220 	bool no_check()           const { return flags & WFL_NO_CHK; }
can_use_gui()221 	bool can_use_gui()        const { return is_local_execution()  &&  !is_scripted(); }
222 
223 	uint16 command_key;// key to toggle action for this function
224 
225 	static vector_tpl<tool_t *> general_tool;
226 	static vector_tpl<tool_t *> simple_tool;
227 	static vector_tpl<tool_t *> dialog_tool;
228 	static vector_tpl<toolbar_t *> toolbar_tool;
229 
230 	static void update_toolbars();
231 
232 	// since only a single toolstr a time can be visible ...
233 	static char toolstr[1024];
234 
235 	static void init_menu();
236 	static void exit_menu();
237 
238 	static void read_menu(const std::string &objfilename);
239 
240 	static uint16 const dummy_id = 0xFFFFU;
241 
tool_t(uint16 const id)242 	tool_t(uint16 const id) : id(id), cursor_area(1,1)
243 	{
244 		cursor = icon = IMG_EMPTY;
245 		ok_sound = NO_SOUND;
246 		offset = Z_PLAN;
247 		default_param = NULL;
248 		command_key = 0;
249 		cursor_centered = false;
250 		flags = 0;
251 		callback_id = 0;
252 	}
253 
~tool_t()254 	virtual ~tool_t() {}
255 
get_icon(player_t *)256 	virtual image_id get_icon(player_t *) const { return icon; }
set_icon(image_id i)257 	void set_icon(image_id i) { icon = i; }
258 
259 	// returns default_param of this tool for player
260 	// if player==NULL returns default_param that was used to create the tool
261 	virtual const char* get_default_param(player_t* = NULL) const { return default_param; }
set_default_param(const char * str)262 	void set_default_param(const char* str) { default_param = str; }
263 
264 	// transfer additional information in networkgames
rdwr_custom_data(memory_rw_t *)265 	virtual void rdwr_custom_data(memory_rw_t*) { }
266 
267 	// this will draw the tool with some indication, if active
268 	virtual bool is_selected() const;
269 
270 	// when true, local execution would do no harm
is_init_network_save()271 	virtual bool is_init_network_save() const { return false; }
is_move_network_save(player_t *)272 	virtual bool is_move_network_save(player_t *) const { return true; }
273 
274 	// if is_work_network_save()==false
275 	// and is_work_here_network_save(...)==false
276 	// then work-command is sent over network
is_work_network_save()277 	virtual bool is_work_network_save() const { return false; }
is_work_here_network_save(player_t *,koord3d)278 	virtual bool is_work_here_network_save(player_t *, koord3d) { return false; }
279 
280 	// will draw a dark frame, if selected
281 	virtual void draw_after(scr_coord pos, bool dirty) const;
282 
get_tooltip(const player_t *)283 	virtual const char *get_tooltip(const player_t *) const { return NULL; }
284 
285 	/**
286 	 * @return true if this tool operates over the grid, not the map tiles.
287 	 */
is_grid_tool()288 	virtual bool is_grid_tool() const {return false;}
289 
290 	/**
291 	 * Returning false on init will automatically invoke previous tool.
292 	 * Returning true will select tool and will make it possible to call work.
293 	 */
init(player_t *)294 	virtual bool init( player_t * ) { return true; }
295 
296 	/// initializes cursor (icon, marked area)
297 	void init_cursor( zeiger_t * ) const;
298 
299 	// returning true on exit will have tool_selector resets to query-tool on right-click
exit(player_t *)300 	virtual bool exit( player_t * ) { return true; }
301 
302 	/* the return string can have different meanings:
303 	 * NULL: ok
304 	 * "": unspecified error
305 	 * "blabla": errors message, will be handled and translated as appropriate
306 	 * check: called before work (and move too?) koord3d already valid coordinate, checks visibility
307 	 * work / move should depend on undergroundmode for not network safe tools
308 	 */
309 	virtual const char *check_pos( player_t *, koord3d );
work(player_t *,koord3d)310 	virtual const char *work( player_t *, koord3d ) { return NULL; }
move(player_t *,uint16,koord3d)311 	virtual const char *move( player_t *, uint16 /* buttonstate */, koord3d ) { return ""; }
312 
313 	/**
314 	 * Should be overloaded if derived class implements move,
315 	 * move will only be called, if this function returns true.
316 	 */
move_has_effects()317 	virtual bool move_has_effects() const { return false;}
318 
319 	/**
320 	 * Returns whether the 2d koordinate passed it's a valid position for this tool to highlight a tile,
321 	 * just takes into account is_grid_tool. It does not check if work is allowed there, that's check_pos() work.
322 	 * @see check_pos
323 	 * @return true is the coordinate it's found valid, false otherwise.
324 	 */
325 	bool check_valid_pos( koord k ) const;
326 
327 	/**
328 	 * Specifies if the cursor will need a position update after this tool takes effect (ie: changed the height of the tile)
329 	 * @note only used on lower_raise tools atm.
330 	 * @return true if the cursor has to be moved.
331 	 */
update_pos_after_use()332 	virtual bool update_pos_after_use() const { return false; }
333 
get_waytype()334 	virtual waytype_t get_waytype() const { return invalid_wt; }
335 };
336 
337 /*
338  * Class for tools that work only on ground (kartenboden)
339  */
340 class kartenboden_tool_t : public tool_t {
341 public:
kartenboden_tool_t(uint16 const id)342 	kartenboden_tool_t(uint16 const id) : tool_t(id) {}
343 
344 	char const* check_pos(player_t*, koord3d) OVERRIDE;
345 };
346 
347 /*
348  * Class for tools needing two clicks (e.g. building ways).
349  * Dragging is also possible.
350  * @author Gerd Wachsmuth
351  */
352 class two_click_tool_t : public tool_t {
353 public:
two_click_tool_t(uint16 const id)354 	two_click_tool_t(uint16 const id) : tool_t(id) {
355 		MEMZERO(start_marker);
356 		first_click_var = true;
357 	}
358 
359 	void rdwr_custom_data(memory_rw_t*) OVERRIDE;
360 	bool init(player_t*) OVERRIDE;
exit(player_t * const player)361 	bool exit(player_t* const player) OVERRIDE { return init(player); }
362 
363 	char const* work(player_t*, koord3d) OVERRIDE;
364 	char const* move(player_t*, uint16 /* buttonstate */, koord3d) OVERRIDE;
move_has_effects()365 	bool move_has_effects() const OVERRIDE { return true; }
366 
367 	bool is_work_here_network_save(player_t *, koord3d) OVERRIDE;
368 
369 	/**
370 	 * @returns true if cleanup() needs to be called before another tool can be executed
371 	 * necessary for all tools that create dummy tiles for preview
372 	 */
remove_preview_necessary()373 	virtual bool remove_preview_necessary() const { return false; }
374 
375 	bool is_first_click() const;
376 
377 	/**
378 	 * Remove dummy grounds, remove start_marker.
379 	 */
cleanup()380 	void cleanup() { cleanup(true); }
381 
get_start_pos()382 	const koord3d& get_start_pos() const { return start; }
383 
384 private:
385 	/**
386 	 * Remove dummy grounds, remove start_marker if @p delete_start_marker is true.
387 	 */
388 	void cleanup(bool delete_start_marker );
389 
390 	/*
391 	 * This routine should fill marked_tiles.
392 	 */
393 	virtual void mark_tiles( player_t *, const koord3d &start, const koord3d &end ) = 0;
394 
395 	/*
396 	 * This routine is called, if the real work should be done.
397 	 * If the tool supports single clicks, end is sometimes == koord3d::invalid.
398 	 * Returned string is passed by work/move.
399 	 */
400 	virtual const char *do_work( player_t *, const koord3d &start, const koord3d &end ) = 0;
401 
402 	/*
403 	 * Can the tool start/end on pos? If it is the second click, start is the position of the first click
404 	 * 0 = no
405 	 * 1 = This tool can work on this tile (with single click)
406 	 * 2 = On this tile can dragging start/end
407 	 * 3 = Both (1 and 2)
408 	 * error will contain an error message (if this is != NULL, return value should be 0).
409 	 */
410 	virtual uint8 is_valid_pos( player_t *, const koord3d &pos, const char *&error, const koord3d &start ) = 0;
411 
412 	virtual image_id get_marker_image();
413 
414 	bool first_click_var;
415 	koord3d start;
416 
417 	zeiger_t *start_marker;
418 
419 protected:
420 	virtual void start_at( koord3d &new_start );
421 
422 	slist_tpl< zeiger_t* > marked;
423 };
424 
425 /* toolbar are a new overclass */
426 class toolbar_t : public tool_t {
427 protected:
428 	const char *helpfile;
429 	tool_selector_t *tool_selector;
430 	slist_tpl<tool_t *>tools;
431 public:
toolbar_t(uint16 const id,char const * const t,char const * const h)432 	toolbar_t(uint16 const id, char const* const t, char const* const h) : tool_t(id)
433 	{
434 		default_param = t;
435 		helpfile = h;
436 		tool_selector = NULL;
437 	}
get_tooltip(player_t const *)438 	char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate(default_param); }
get_tool_selector()439 	tool_selector_t *get_tool_selector() const { return tool_selector; }
440 	image_id get_icon(player_t*) const OVERRIDE;
441 	bool is_selected() const OVERRIDE;
is_init_network_save()442 	bool is_init_network_save() const OVERRIDE { return true; }
is_work_network_save()443 	bool is_work_network_save() const OVERRIDE { return true; }
444 	// show this toolbar
445 	bool init(player_t*) OVERRIDE;
446 	// close this toolbar
447 	bool exit(player_t*) OVERRIDE;
448 	virtual void update(player_t *);	// just refresh content
append(tool_t * tool)449 	void append(tool_t *tool) { tools.append(tool); }
450 };
451 
452 #define MAX_LAST_TOOLS (10)
453 
454 class toolbar_last_used_t : public toolbar_t {
455 private:
456 	slist_tpl<tool_t *>all_tools[MAX_PLAYER_COUNT];
457 public:
toolbar_last_used_t(uint16 const id,char const * const t,char const * const h)458 	toolbar_last_used_t(uint16 const id, char const* const t, char const* const h) : toolbar_t(id,t,h) {}
459 	static toolbar_last_used_t *last_used_tools;
460 	void update(player_t *) OVERRIDE;	// just refresh content
461 	void append(tool_t *, player_t *);
462 	void clear();
463 };
464 
465 // create new instance of tool
466 tool_t *create_tool(int toolnr);
467 
468 #endif
469