1 /*
2  * Tools for the players
3  *
4  * Copyright (c) 1997 - 2001 Hj. Malthaner
5  *
6  * This file is part of the Simutrans project under the artistic license.
7  * (see license.txt)
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <math.h>
13 
14 #include "simdebug.h"
15 #include "simevent.h"
16 #include "simcity.h"
17 #include "simmesg.h"
18 #include "simconvoi.h"
19 #include "gui/simwin.h"
20 #include "display/viewport.h"
21 
22 #include "bauer/fabrikbauer.h"
23 #include "bauer/vehikelbauer.h"
24 
25 #include "boden/grund.h"
26 #include "boden/wasser.h"
27 #include "boden/wege/schiene.h"
28 #include "boden/tunnelboden.h"
29 #include "boden/monorailboden.h"
30 
31 #include "simdepot.h"
32 #include "simfab.h"
33 #include "display/simimg.h"
34 #include "simintr.h"
35 #include "simhalt.h"
36 #include "simskin.h"
37 
38 #include "descriptor/ground_desc.h"
39 #include "descriptor/building_desc.h"
40 #include "descriptor/roadsign_desc.h"
41 #include "descriptor/tunnel_desc.h"
42 
43 #include "vehicle/simvehicle.h"
44 #include "vehicle/simroadtraffic.h"
45 #include "vehicle/simpeople.h"
46 
47 #include "gui/line_management_gui.h"
48 #include "gui/tool_selector.h"
49 #include "gui/station_building_select.h"
50 #include "gui/minimap.h" // to update map after construction of new industry
51 #include "gui/depot_frame.h"
52 #include "gui/schedule_gui.h"
53 #include "gui/player_frame_t.h"
54 #include "gui/schedule_list.h"
55 #include "gui/signal_spacing.h"
56 #include "gui/city_info.h"
57 #include "gui/trafficlight_info.h"
58 #include "gui/privatesign_info.h"
59 #include "gui/messagebox.h"
60 
61 #include "obj/zeiger.h"
62 #include "obj/bruecke.h"
63 #include "obj/tunnel.h"
64 #include "obj/groundobj.h"
65 #include "obj/signal.h"
66 #include "obj/crossing.h"
67 #include "obj/roadsign.h"
68 #include "obj/wayobj.h"
69 #include "obj/leitung2.h"
70 #include "obj/baum.h"
71 #include "obj/field.h"
72 #include "obj/label.h"
73 
74 #include "dataobj/koord.h"
75 #include "dataobj/settings.h"
76 #include "dataobj/environment.h"
77 #include "dataobj/schedule.h"
78 #include "dataobj/route.h"
79 #include "dataobj/scenario.h"
80 #include "network/network_cmd_ingame.h" // for dragging raise / lower tools
81 
82 #include "bauer/tunnelbauer.h"
83 #include "bauer/brueckenbauer.h"
84 #include "bauer/wegbauer.h"
85 #include "bauer/hausbauer.h"
86 
87 #include "descriptor/way_desc.h"
88 #include "descriptor/roadsign_desc.h"
89 
90 #include "tpl/vector_tpl.h"
91 
92 #include "network/memory_rw.h"
93 #include "utils/simrandom.h"
94 #include "utils/simstring.h"
95 
96 #include "simtool.h"
97 #include "player/finance.h"
98 
99 
100 #define is_scenario()  welt->get_scenario()->is_scripted()
101 
102 #define CHECK_FUNDS() \
103 	/* do not allow, if out of money */ \
104 	if(  !welt->get_settings().is_freeplay()  &&  player->get_player_nr()!=1  &&  !player->has_money_or_assets() ) {\
105 		return "Out of funds";\
106 	}\
107 
108 /****************************************** notification strings **************************************/
109 
110 /**
111  * Translated notification text identifiers used by tools are placed here.
112  * This is because they are not simple well structured internal identifiers.
113  * Instead they can be complex sentences intended to be read untranslated.
114  * Using these constants assues a valid and correct text identifier is choosen.
115  */
116 
117 
118 
119 /**
120  * Message returned when a player cannot afford to complete an action.
121  */
122 char const *const NOTICE_INSUFFICIENT_FUNDS = "Insufficient funds!";
123 
124 /**
125  * Message returned when a player tries to place trees when trees are disabled.
126  */
127 char const *const NOTICE_NO_TREES = "Trees disabled!";
128 
129 /**
130  * Message returned when valid terrain cannot be found for a tool to use.
131  */
132 char const *const NOTICE_UNSUITABLE_GROUND = "No suitable ground!";
133 
134 /**
135  * Message returned when a depot cannot be placed.
136  */
137 char const *const NOTICE_DEPOT_BAD_POS = "Cannot built depot here!";
138 
139 /**
140  * Message returned when a tool fails due to the target tile being occupied.
141  */
142 char const *const NOTICE_TILE_FULL = "Tile not empty.";
143 
144 /**
145  * Message returned when a company tries to make a public way when public ways are disabled.
146  */
147 char const *const NOTICE_DISABLED_PUBLIC_WAY = "Not allowed to make publicly owned ways!";
148 
149 /****************************************** static helper functions **************************************/
150 
151 /**
152  * Creates a tooltip from tip text and money value
153  * @author Hj. Malthaner
154  */
tooltip_with_price(const char * tip,sint64 price)155 char *tooltip_with_price(const char * tip, sint64 price)
156 {
157 	const int n = sprintf(tool_t::toolstr, "%s, ", translator::translate(tip) );
158 	money_to_string(tool_t::toolstr+n, (double)price/-100.0);
159 	return tool_t::toolstr;
160 }
161 
162 
163 
164 
165 /**
166  * Creates a tooltip from tip text, money value and way/object length
167  * @author captain crunch
168  */
tooltip_with_price_length(const char * tip,sint64 price,sint64 length)169 char *tooltip_with_price_length(const char * tip, sint64 price, sint64 length)
170 {
171 	int n;
172 	n = sprintf(tool_t::toolstr, translator::translate("length: %d"), length);
173 	n += sprintf(tool_t::toolstr+n, ", %s: ", translator::translate(tip));
174 	money_to_string(tool_t::toolstr+n, (double)price/-100.0);
175 	return tool_t::toolstr;
176 }
177 
178 
179 
180 
181 /**
182  * Creates a tooltip from tip text and money value
183  * @author Hj. Malthaner
184  */
tooltip_with_price_maintenance(karte_t * welt,const char * tip,sint64 price,sint64 maintenance)185 char *tooltip_with_price_maintenance(karte_t *welt, const char *tip, sint64 price, sint64 maintenance)
186 {
187 	int n = sprintf(tool_t::toolstr, "%s, ", translator::translate(tip) );
188 	money_to_string(tool_t::toolstr+n, (double)price/-100.0);
189 	strcat( tool_t::toolstr, " (" );
190 	n = strlen(tool_t::toolstr);
191 
192 	money_to_string(tool_t::toolstr+n, (double)(welt->scale_with_month_length(maintenance) ) / 100.0);
193 	strcat( tool_t::toolstr, ")" );
194 	return tool_t::toolstr;
195 }
196 
197 
198 
199 /**
200  * Creates a tooltip from tip text and money value
201  */
tooltip_with_price_maintenance_capacity(karte_t * const welt,char const * const tip,sint64 const price,sint64 const maintenance,uint32 const capacity,uint8 const enables)202 static char const* tooltip_with_price_maintenance_capacity(karte_t* const welt, char const* const tip, sint64 const price, sint64 const maintenance, uint32 const capacity, uint8 const enables)
203 {
204 	int n = sprintf(tool_t::toolstr, "%s, ", translator::translate(tip) );
205 	money_to_string(tool_t::toolstr+n, (double)price/-100.0);
206 	strcat( tool_t::toolstr, " (" );
207 	n = strlen(tool_t::toolstr);
208 
209 	money_to_string(tool_t::toolstr+n, (double)(welt->scale_with_month_length(maintenance) ) / 100.0);
210 	strcat( tool_t::toolstr, ")" );
211 	n = strlen(tool_t::toolstr);
212 
213 	if((enables&7)!=0) {
214 		n += sprintf( tool_t::toolstr+n, ", %d", capacity );
215 		if(enables&1) {
216 			n += sprintf( tool_t::toolstr+n, " %s", translator::translate("Passagiere") );
217 		}
218 		if(enables&2) {
219 			n += sprintf( tool_t::toolstr+n, " %s", translator::translate("Post") );
220 		}
221 		if(enables&4) {
222 			n += sprintf( tool_t::toolstr+n, " %s", translator::translate("Fracht") );
223 		}
224 	}
225 	else if (!welt->get_settings().is_separate_halt_capacities()) {
226 		n += sprintf( tool_t::toolstr+n, ", %s %d", translator::translate("Storage capacity"), capacity );
227 	}
228 
229 	return tool_t::toolstr;
230 }
231 
232 
open_error_msg_win(const char * error)233 void open_error_msg_win(const char* error)
234 {
235 	koord pos = message_t::get_coord_from_text(error);
236 	if (pos != koord::invalid) {
237 		create_win( new news_loc(error, pos), w_time_delete, magic_none);
238 	}
239 	else {
240 		create_win( new news_img(error), w_time_delete, magic_none);
241 	}
242 }
243 
244 
245 /**
246  * sucht Haltestelle um Umkreis +1/-1 um (pos, b, h)
247  * extended to search first in our direction
248  * @author Hj. Malthaner, V.Meyer, prissi
249  */
suche_nahe_haltestelle(player_t * player,karte_t * welt,koord3d pos,sint16 b=1,sint16 h=1)250 static halthandle_t suche_nahe_haltestelle(player_t *player, karte_t *welt, koord3d pos, sint16 b=1, sint16 h=1)
251 {
252 	koord k(pos.get_2d());
253 
254 	// any other ground with a valid stop here?
255 	halthandle_t my_halt;
256 	if(  planquadrat_t* plan=welt->access(pos.get_2d())  ) {
257 		my_halt = plan->get_halt( player );
258 		if(  my_halt.is_bound()  ) {
259 			return my_halt;
260 		}
261 	}
262 
263 	grund_t *bd = welt->lookup(pos);
264 	if(  bd==NULL  ) {
265 		bd = welt->lookup_kartenboden(k);
266 	}
267 
268 	// first we try to connect to a stop straight in our direction; otherwise our station may break during construction
269 	if(  bd->hat_wege()  ) {
270 		ribi_t::ribi ribi = bd->get_weg_nr(0)->get_ribi_unmasked();
271 		for(  int i=0;  i<4;  i++ ) {
272 			if(  ribi_t::nsew[i] & ribi ) {
273 				if(  planquadrat_t* plan=welt->access(k+koord::nsew[i])  ) {
274 					my_halt = plan->get_halt( player );
275 					if(  my_halt.is_bound()  ) {
276 						return my_halt;
277 					}
278 				}
279 			}
280 		}
281 	}
282 
283 	// now just search all neighbours
284 	for(  sint16 y=-1;  y<=h;  y++  ) {
285 		for(  sint16 x=-1;  x<=b;  (x==-1 && y>-1 && y<h) ? x=b:x++  ) {
286 			if(  planquadrat_t* plan=welt->access(k+koord(x,y))  ) {
287 				my_halt = plan->get_halt( player );
288 				if(  my_halt.is_bound()  ) {
289 					return my_halt;
290 				}
291 			}
292 		}
293 	}
294 
295 #if AUTOJOIN_PUBLIC
296 	// now search everything for public stops
297 	for(  int i=0;  i<8;  i++ ) {
298 		if(  planquadrat_t* plan=welt->access(k+koord::neighbours[i])  ) {
299 			my_halt = plan->get_halt( welt->get_public_player() );
300 			if(  my_halt.is_bound()  ) {
301 				return my_halt;
302 			}
303 		}
304 	}
305 #endif
306 
307 	// here we reach only with a non-found station, i.e. a non-bounded handle
308 	return halthandle_t();
309 }
310 
311 
312 // converts a 2d koord to a suitable ground pointer
tool_intern_koord_to_weg_grund(player_t * player,karte_t * welt,koord3d pos,waytype_t wt)313 static grund_t *tool_intern_koord_to_weg_grund(player_t *player, karte_t *welt, koord3d pos, waytype_t wt)
314 {
315 	// check for valid ground
316 	grund_t *gr=welt->lookup(pos);
317 	if (gr==NULL) {
318 		return NULL;
319 	}
320 
321 	if(  wt==powerline_wt  &&  gr->get_leitung()  ) {
322 		// check for ownership
323 		if(gr->get_leitung()->is_deletable(player)!=NULL) {
324 			return NULL;
325 		}
326 		// ok
327 		else {
328 			return gr;
329 		}
330 	}
331 
332 	// tram
333 	if(wt==tram_wt) {
334 		weg_t *way = gr->get_weg(track_wt);
335 		if (way  &&  way->get_desc()->get_styp() == type_tram &&  way->is_deletable(player)==NULL) {
336 			return gr;
337 		}
338 		else {
339 			return NULL;
340 		}
341 	}
342 
343 
344 	// has some rail or monorail?
345 	if(  !gr->hat_weg(wt)  ) {
346 		return NULL;
347 	}
348 	// check for ownership
349 	if(gr->get_weg(wt)->is_deletable(player)!=NULL){
350 		return NULL;
351 	}
352 	// ok, now we have a valid ground
353 	return gr;
354 }
355 
356 
357 
358 /****************************************** now the actual tools **************************************/
work(player_t *,koord3d pos)359 const char *tool_query_t::work( player_t *, koord3d pos )
360 {
361 	grund_t *gr = welt->lookup(pos);
362 	if(gr) {
363 		// not single_info: show least important first
364 		const bool reverse = !env_t::single_info  ||  is_ctrl_pressed();
365 
366 		// iterate through different stages of importance
367 		const uint8 max_stages = 4;
368 		for(uint8 stage = 0; stage<max_stages; stage++) {
369 
370 			int old_count = win_get_open_count();
371 
372 			switch (reverse ? max_stages-1-stage: stage) {
373 				case 0: { // halts
374 					if(  gr->get_halt().is_bound()  ) {
375 						gr->get_halt()->open_info_window();
376 					}
377 					break;
378 				}
379 				case 1: // labels
380 					if(  gr->get_flag(grund_t::marked)  ) {
381 						label_t *lb = gr->find<label_t>();
382 						if(  lb  ) {
383 							lb->show_info();
384 							if(  old_count < win_get_open_count()  ) {
385 								return NULL;
386 							}
387 						}
388 					}
389 					break;
390 				case 2: { // objects
391 					convoihandle_t cnv;
392 					for (size_t n = gr->get_top(); n-- != 0;) {
393 						obj_t *obj = gr->obj_bei(reverse ? gr->get_top()-1-n : n);
394 
395 						if (vehicle_t* veh = dynamic_cast<vehicle_t*>(obj)) {
396 							if (veh->get_convoi()->self == cnv) {
397 								continue; // do not try to open the same window twice, does not work so great with env_t::second_open_closes_win
398 							}
399 							cnv = veh->get_convoi()->self;
400 						}
401 						if(  obj && obj->get_typ()!=obj_t::wayobj && obj->get_typ()!=obj_t::pillar && obj->get_typ()!=obj_t::label  ) {
402 							DBG_MESSAGE("tool_query_t()", "index %u", (unsigned)n);
403 							obj->show_info();
404 							// did some new window open?
405 							if(env_t::single_info  &&  old_count < win_get_open_count()) {
406 								return NULL;
407 							}
408 							old_count = win_get_open_count(); // click may have closed a window, open a new one if possible
409 						}
410 					}
411 					break;
412 				}
413 				case 3:
414 				default: // ground
415 					gr->open_info_window();
416 					break;
417 			}
418 
419 			if(  env_t::single_info  &&  old_count < win_get_open_count()  ) {
420 				return NULL;
421 			}
422 		}
423 	}
424 	return NULL;
425 }
426 
427 
428 /* delete things from a tile
429  * citycars and pedestrian first and then go up to queue to more important objects
430  */
tool_remover_intern(player_t * player,koord3d pos,sint8 type,const char * & msg)431 bool tool_remover_t::tool_remover_intern(player_t *player, koord3d pos, sint8 type, const char *&msg)
432 {
433 DBG_MESSAGE("tool_remover_intern()","at (%s)", pos.get_str());
434 	// check if there is something to remove from here ...
435 	grund_t *gr = welt->lookup(pos);
436 	if (!gr  ||  gr->get_top()==0) {
437 		msg = "";
438 		return false;
439 	}
440 
441 	// marker?
442 	if (type == obj_t::label  ||  type == obj_t::undefined) {
443 		if (label_t* l = gr->find<label_t>()) {
444 			msg = l->is_deletable(player);
445 			if(msg==NULL) {
446 				delete l;
447 				return true;
448 			}
449 			else if(  gr->get_top()==1  ||  type == obj_t::label  ) {
450 				// only complain if this is the last object on this tile ...
451 				return false;
452 			}
453 			msg = NULL;
454 			// not deletable: skip it
455 		}
456 	}
457 
458 	// citycar? (we allow always)
459 	if (type == obj_t::road_vehicle  ||  type == obj_t::undefined) {
460 		if (private_car_t* citycar = gr->find<private_car_t>()) {
461 			delete citycar;
462 			return true;
463 		}
464 	}
465 	// pedestrians?
466 	if (type == obj_t::pedestrian  ||  type == obj_t::undefined) {
467 		if (pedestrian_t* pedestrian = gr->find<pedestrian_t>()) {
468 			delete pedestrian;
469 			return true;
470 		}
471 	}
472 
473 	koord k(pos.get_2d());
474 
475 	// prissi: check powerline (can cross ground of another player)
476 	leitung_t* lt = gr->get_leitung();
477 	// check whether powerline related stuff should be removed, and if there is any to remove
478 	if (  (type == obj_t::leitung  ||  type == obj_t::pumpe  ||  type == obj_t::senke  ||  type == obj_t::undefined)
479 	       &&  lt != NULL  &&  lt->is_deletable(player) == NULL) {
480 		if(  gr->ist_bruecke()  ) {
481 			bruecke_t* br = gr->find<bruecke_t>();
482 			if(  br == NULL  ) {
483 				// no bridge? most likely transformer on a former bridge tile...
484 				grund_t *gr_new = new boden_t(pos, gr->get_grund_hang());
485 				gr_new->take_obj_from( gr );
486 				welt->access(k)->kartenboden_setzen( gr_new );
487 				gr = gr_new;
488 			}
489 			else if(  br->get_desc()->get_waytype() == powerline_wt  ) {
490 				msg = bridge_builder_t::remove(player, gr->get_pos(), powerline_wt );
491 				return msg == NULL;
492 			}
493 		}
494 		if(gr->ist_tunnel()  &&  gr->ist_karten_boden()) {
495 			if (gr->find<tunnel_t>()->get_desc()->get_waytype()==powerline_wt) {
496 				msg = tunnel_builder_t::remove(player, gr->get_pos(), powerline_wt, is_ctrl_pressed() );
497 				return msg == NULL;
498 			}
499 		}
500 		if(  gr->ist_im_tunnel()  ) {
501 			lt->cleanup(player);
502 			delete lt;
503 			// now everything gone?
504 			if(  gr->get_top() == 1  ) {
505 				// delete tunnel too
506 				tunnel_t *t = gr->find<tunnel_t>();
507 				t->cleanup(player);
508 				delete t;
509 			}
510 			// unmark kartenboden (is marked during underground mode deletion)
511 			welt->lookup_kartenboden(k)->clear_flag(grund_t::marked);
512 			// remove upper or lower ground
513 			welt->access(k)->boden_entfernen(gr);
514 			delete gr;
515 		}
516 		else {
517 			lt->cleanup(player);
518 			delete lt;
519 		}
520 		return true;
521 	}
522 
523 	// check for signal
524 	roadsign_t* rs = gr->find<signal_t>();
525 	if (rs == NULL) rs = gr->find<roadsign_t>();
526 	if ( (type == obj_t::signal  ||  type == obj_t::roadsign  ||  type == obj_t::undefined)  &&  rs!=NULL) {
527 		msg = rs->is_deletable(player);
528 		if(msg) {
529 			return false;
530 		}
531 DBG_MESSAGE("tool_remover()",  "removing roadsign at (%s)", pos.get_str());
532 		weg_t *weg = gr->get_weg(rs->get_desc()->get_wtyp());
533 		if(  weg==NULL  &&  rs->get_desc()->get_wtyp()==tram_wt  ) {
534 			weg = gr->get_weg(track_wt);
535 		}
536 		rs->cleanup(player);
537 		delete rs;
538 		assert( weg );
539 		weg->count_sign();
540 		return true;
541 	}
542 
543 	// check stations
544 	halthandle_t halt = gr->get_halt();
545 DBG_MESSAGE("tool_remover()", "bound=%i",halt.is_bound());
546 	if (gr->is_halt()  &&  halt.is_bound()  &&  fabrik_t::get_fab(k)==NULL  &&  type == obj_t::undefined) {
547 		// halt and not a factory (oil rig etc.)
548 		const player_t* owner = halt->get_owner();
549 		if(  player_t::check_owner( owner, player )  ) {
550 			return haltestelle_t::remove(player, gr->get_pos());
551 		}
552 	}
553 
554 	// catenary or something like this
555 	wayobj_t* wo = gr->find<wayobj_t>();
556 	if(wo  &&  (type == obj_t::wayobj  ||  type == obj_t::undefined)) {
557 		msg = wo->is_deletable(player);
558 		if(msg) {
559 			return false;
560 		}
561 		wo->cleanup(player);
562 		delete wo;
563 		depot_t *dep = gr->get_depot();
564 		if( dep ) {
565 			dep->update_win();
566 		}
567 		return true;
568 	}
569 
570 DBG_MESSAGE("tool_remover()", "check tunnel/bridge");
571 
572 	// bridge?
573 	if(gr->ist_bruecke()  &&  (type == obj_t::bruecke  ||  type == obj_t::undefined)) {
574 DBG_MESSAGE("tool_remover()",  "removing bridge from %d,%d,%d",gr->get_pos().x, gr->get_pos().y, gr->get_pos().z);
575 		bruecke_t* br = gr->find<bruecke_t>();
576 		msg = bridge_builder_t::remove(player, gr->get_pos(), br->get_desc()->get_waytype());
577 		return msg == NULL;
578 	}
579 
580 	// beginning/end of tunnel
581 	if(gr->ist_tunnel()  &&  gr->ist_karten_boden()  &&  (type == obj_t::tunnel  ||  type == obj_t::undefined)) {
582 DBG_MESSAGE("tool_remover()",  "removing tunnel  from %d,%d,%d",gr->get_pos().x, gr->get_pos().y, gr->get_pos().z);
583 		waytype_t wegtyp =  gr->get_leitung() ? powerline_wt : gr->get_weg_nr(0)->get_waytype();
584 		msg = tunnel_builder_t::remove(player, gr->get_pos(), wegtyp, is_ctrl_pressed());
585 		return msg == NULL;
586 	}
587 
588 	// fields
589 	field_t* f = gr->find<field_t>();
590 	if (f  &&  (type == obj_t::field  ||  type == obj_t::undefined)) {
591 		msg = f->is_deletable(player);
592 		if(msg==NULL) {
593 			f->cleanup(player);
594 			delete f;
595 			// fields have foundations ...
596 			sint8 dummy;
597 			welt->access(k)->boden_ersetzen( gr, new boden_t(gr->get_pos(), welt->recalc_natural_slope(k,dummy) ) );
598 			welt->lookup_kartenboden(k)->calc_image();
599 			welt->lookup_kartenboden(k)->set_flag( grund_t::dirty );
600 		}
601 		return msg == NULL;
602 	}
603 
604 	// depots
605 	depot_t* dep = gr->get_depot();
606 	if (dep  &&  (type == obj_t::bahndepot  ||  type == obj_t::undefined)) {
607 		// type == bahndepot to remove any type of depot
608 		msg = dep->is_deletable(player);
609 		if(msg) {
610 			return false;
611 		}
612 		dep->cleanup(player);
613 		delete dep;
614 		return true;
615 	}
616 
617 	// since buildings can have more than one tile, we must handle them together
618 	gebaeude_t* gb = gr->find<gebaeude_t>();
619 	if(gb != NULL  &&  (type == obj_t::gebaeude  ||  type == obj_t::undefined)) {
620 		msg = gb->is_deletable(player);
621 		if(msg) {
622 			return false;
623 		}
624 		if(!gb->get_tile()->get_desc()->can_rotate()  &&  welt->cannot_save()) {
625 			msg = "Not possible in this rotation!";
626 			return false;
627 		}
628 		DBG_MESSAGE("tool_remover()",  "removing building" );
629 
630 		// remove town? (when removing townhall)
631 		if(gb->is_townhall()) {
632 			stadt_t *stadt = welt->find_nearest_city(k);
633 			if(!welt->remove_city( stadt )) {
634 				msg = "Das Feld gehoert\neinem anderen Spieler\n";
635 				return false;
636 			}
637 		}
638 		else {
639 			// townhall is also removed during town removal
640 			hausbauer_t::remove( player, gb );
641 		}
642 		return true;
643 	}
644 
645 	// if type is given, then leave here. Below other stuff and ways gets removed.
646 	if (type != obj_t::undefined) {
647 		msg = "Requested object not found.";
648 		return false;
649 	}
650 
651 	// there is a powerline above this tile, but we do not own it
652 	// so we take it out and add it later again
653 	if(lt) {
654 DBG_MESSAGE("tool_remover()",  "took out powerline");
655 		gr->obj_remove(lt);
656 	}
657 
658 	// do not delete crossing, so we remove it
659 	crossing_t *cr = gr->find<crossing_t>(2);
660 	if(cr) {
661 		gr->obj_remove(cr);
662 	}
663 	// do not delete pointers - they may come from players on other clients
664 	zeiger_t *zeiger = gr->find<zeiger_t>();
665 	if(zeiger) {
666 		gr->obj_remove(zeiger);
667 	}
668 	// do not delete other players label
669 	label_t *label = gr->find<label_t>();
670 	if(label) {
671 		gr->obj_remove(label);
672 	}
673 
674 	// remove all other stuff (clouds, ...)
675 	bool return_ok = false;
676 	uint8 num_obj = gr->obj_count();
677 	if(num_obj>0) {
678 		msg = gr->kann_alle_obj_entfernen(player);
679 		return_ok = (msg==NULL  &&  !(gr->get_typ()==grund_t::brueckenboden  ||  gr->get_typ()==grund_t::tunnelboden)  &&  gr->obj_loesche_alle(player));
680 		DBG_MESSAGE("tool_remover()",  "removing everything from %d,%d,%d",gr->get_pos().x, gr->get_pos().y, gr->get_pos().z);
681 	}
682 
683 	if(lt) {
684 		DBG_MESSAGE("tool_remover()",  "add again powerline");
685 		gr->obj_add(lt);
686 	}
687 	if(cr) {
688 		gr->obj_add(cr);
689 	}
690 	if(zeiger) {
691 		gr->obj_add(zeiger);
692 	}
693 	if(label) {
694 		gr->obj_add(label);
695 	}
696 
697 	// could not delete everything
698 	if(msg) {
699 		return false;
700 	}
701 	if(return_ok) {
702 		// no sound
703 		msg = "";
704 		return true;
705 	}
706 
707 	// ok, now we remove every object that should be removed - one by one.
708 	// the following objects will be removed together
709 DBG_MESSAGE("tool_remover()", "removing way");
710 
711 	waytype_t wt = ignore_wt;
712 	if(gr->get_typ()!=grund_t::tunnelboden  ||  gr->has_two_ways()) {
713 		weg_t *w = gr->get_weg_nr(1);
714 		if(gr->get_typ()==grund_t::brueckenboden  &&  w==NULL) {
715 			// do not delete the middle of a bridge
716 			return false;
717 		}
718 		if(  w  &&  w->get_waytype()==water_wt  ) {
719 			// remove the other way first
720 			w = NULL;
721 		}
722 		if(w==NULL  ||  w->is_deletable(player)!=NULL) {
723 			w = gr->get_weg_nr(0);
724 			if(w==NULL) {
725 				// no way at all ...
726 				return true;
727 			}
728 			if(w->is_deletable(player)!=NULL){
729 				msg = w->is_deletable(player);
730 				return false;
731 			}
732 		}
733 		wt = w->get_desc()->get_finance_waytype();
734 		sint32 cost_sum = gr->weg_entfernen(w->get_waytype(), true);
735 		player_t::book_construction_costs(player, -cost_sum, k, wt);
736 	}
737 	else {
738 		// remove ways and tunnel
739 		if(  weg_t *weg = gr->get_weg_nr(0)  ) {
740 			gr->remove_everything_from_way(player, weg->get_waytype(), ribi_t::none);
741 		}
742 		// tunnel without way: delete anything else
743 		if(  !gr->hat_wege()  ) {
744 			gr->obj_loesche_alle(player);
745 		}
746 	}
747 
748 	// remove empty tile
749 	if(  !gr->ist_karten_boden()  &&  gr->get_top()==0  ) {
750 		// unmark kartenboden (is marked during underground mode deletion)
751 		welt->lookup_kartenboden(k)->clear_flag(grund_t::marked);
752 		// remove upper or lower ground
753 		welt->access(k)->boden_entfernen(gr);
754 		delete gr;
755 	}
756 
757 	return true;
758 }
759 
760 
761 
work(player_t * player,koord3d pos)762 const char *tool_remover_t::work( player_t *player, koord3d pos )
763 {
764 	DBG_MESSAGE("tool_remover()","at %d,%d", pos.x, pos.y);
765 
766 	obj_t::typ type = obj_t::undefined;
767 
768 	if (default_param) {
769 		int t = atoi(default_param);
770 		if (t != 0  &&  -1 <= t  &&  t <= 200) {
771 			type = (obj_t::typ)t;
772 		}
773 	}
774 
775 	const char *fail = NULL;
776 	if(!tool_remover_intern(player, pos, type, fail)) {
777 		return fail;
778 	}
779 
780 	// must recalc neighbourhood for slopes etc.
781 	if(pos.x>1) {
782 		welt->lookup_kartenboden(pos.get_2d()+koord::west)->calc_image();
783 	}
784 	if(pos.y>1) {
785 		welt->lookup_kartenboden(pos.get_2d()+koord::north)->calc_image();
786 	}
787 
788 	if(pos.x<welt->get_size().x-1) {
789 		welt->lookup_kartenboden(pos.get_2d()+koord::east)->calc_image();
790 	}
791 	if(pos.y<welt->get_size().y-1) {
792 		welt->lookup_kartenboden(pos.get_2d()+koord::south)->calc_image();
793 	}
794 
795 	return NULL;
796 }
797 
798 
799 
move(player_t * player,uint16 buttonstate,koord3d pos)800 const char *tool_raise_lower_base_t::move( player_t *player, uint16 buttonstate, koord3d pos )
801 {
802 	CHECK_FUNDS();
803 
804 	const char *result = NULL;
805 	if(  buttonstate==1  ) {
806 		char buf[16];
807 		if(!is_dragging) {
808 			drag_height = get_drag_height(pos.get_2d());
809 		}
810 		is_dragging = true;
811 		sprintf( buf, "%i", drag_height );
812 		default_param = buf;
813 		if (env_t::networkmode) {
814 			// queue tool for network
815 			nwc_tool_t *nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false);
816 			network_send_server(nwc);
817 		}
818 		else {
819 			result = work( player, pos );
820 		}
821 		default_param = NULL;
822 	}
823 	return result;
824 }
825 
826 
drag(player_t * player,koord k,sint16 height,int & n)827 const char* tool_raise_lower_base_t::drag(player_t *player, koord k, sint16 height, int &n)
828 {
829 	if(  !welt->is_within_grid_limits(k)  ) {
830 		return "";
831 	}
832 	const char* err = NULL;
833 
834 	// dragging may be going up or down!
835 	while(  welt->lookup_hgt(k) < height  &&  height <= welt->get_maximumheight()  ) {
836 		int diff = welt->grid_raise( player, k, err );
837 		if(  diff == 0  ) {
838 			break;
839 		}
840 		n += diff;
841 	}
842 
843 	// when going down need to check here we will not be going below sea level
844 	// cannot rely on check within lower as water height can be recalculated
845 	while(  height >= welt->get_water_hgt(k)  &&  welt->lookup_hgt(k) > height  &&  height >= welt->get_minimumheight()  ) {
846 		int diff = welt->grid_lower( player, k, err );
847 		if(  diff == 0  ) {
848 			break;
849 		}
850 		n += diff;
851 	}
852 
853 	return err; //height == welt->lookup_hgt(k);
854 }
855 
856 
check_dragging()857 bool tool_raise_lower_base_t::check_dragging()
858 {
859 	// reset dragging
860 	if(  is_dragging  &&  strempty(default_param)  ) {
861 		is_dragging = false;
862 		return false;
863 	}
864 	return true;
865 }
866 
867 
get_drag_height(koord k)868 sint16 tool_raise_t::get_drag_height(koord k)
869 {
870 	const grund_t *gr = welt->lookup_kartenboden_gridcoords(k);
871 
872 	return  gr->get_hoehe(welt->get_corner_to_operate(k)) + 1;
873 }
874 
875 
check_pos(player_t *,koord3d pos)876 const char *tool_raise_t::check_pos(player_t *, koord3d pos )
877 {
878 	// check for underground mode
879 	if(  is_dragging  &&  drag_height-1 > grund_t::underground_level  ) {
880 		is_dragging = false;
881 		return "";
882 	}
883 	if(  !welt->is_within_grid_limits(pos.get_2d())  ) {
884 		return "";
885 	}
886 	sint8 h = (sint8) get_drag_height(pos.get_2d());
887 	if(  h > grund_t::underground_level  ) {
888 		return "Terraforming not possible\nhere in underground view";
889 	}
890 	return NULL;
891 }
892 
893 
work(player_t * player,koord3d pos)894 const char *tool_raise_t::work(player_t* player, koord3d pos )
895 {
896 	if (!check_dragging()) {
897 		return NULL;
898 	}
899 
900 	const char* err = NULL;
901 	koord k = pos.get_2d();
902 
903 	CHECK_FUNDS();
904 
905 	if(welt->is_within_grid_limits(k)) {
906 
907 		const sint8 hgt = (sint8) get_drag_height(k);
908 
909 		if(  hgt <= welt->get_maximumheight()  ) {
910 
911 			int n = 0;	// tiles changed
912 			if(  !strempty(default_param)  ) {
913 				// called by dragging or by AI
914 				err = drag(player, k, atoi(default_param), n);
915 			}
916 			else {
917 				n = welt->grid_raise(player, k, err);
918 			}
919 			if(n>0) {
920 				player_t::book_construction_costs(player, welt->get_settings().cst_alter_land * n, k, ignore_wt);
921 			}
922 			return err == NULL ? (n ? NULL : "")
923 			                   : (*err == 0 ? NOTICE_TILE_FULL : err);
924 		}
925 		else {
926 			// no mountains higher than welt->get_maximumheight() ...
927 			return "Maximum tile height difference reached.";
928 		}
929 	}
930 	return "Zu nah am Kartenrand";
931 }
932 
933 
get_drag_height(koord k)934 sint16 tool_lower_t::get_drag_height(koord k)
935 {
936 	const grund_t *gr = welt->lookup_kartenboden_gridcoords(k);
937 
938 	return  gr->get_hoehe(welt->get_corner_to_operate(k)) - 1;
939 }
940 
941 
check_pos(player_t *,koord3d pos)942 const char *tool_lower_t::check_pos( player_t *, koord3d pos )
943 {
944 	// check for underground mode
945 	if (is_dragging  &&  drag_height+1 > grund_t::underground_level) {
946 		is_dragging = false;
947 		return "";
948 	}
949 	if (! welt->is_within_grid_limits(pos.get_2d())) {
950 		return "";
951 	}
952 	sint8 h = (sint8) get_drag_height(pos.get_2d());
953 	if (h > grund_t::underground_level) {
954 			return "Terraforming not possible\nhere in underground view";
955 	}
956 	return NULL;
957 }
958 
959 
work(player_t * player,koord3d pos)960 const char *tool_lower_t::work( player_t *player, koord3d pos )
961 {
962 	if (!check_dragging()) {
963 		return NULL;
964 	}
965 
966 	const char* err = NULL;
967 	koord k = pos.get_2d();
968 
969 	CHECK_FUNDS();
970 
971 	if(welt->is_within_grid_limits(k)) {
972 		const sint8 hgt = (sint8) get_drag_height(k);
973 
974 		if(  hgt >= welt->get_water_hgt( k )  ) {
975 			int n = 0; // tiles changed
976 			if (!strempty(default_param)) {
977 				// called by dragging or by AI
978 				err = drag(player, k, atoi(default_param), n);
979 			}
980 			else {
981 				n = welt->grid_lower(player, k, err);
982 			}
983 			if(n>0) {
984 				player_t::book_construction_costs(player, welt->get_settings().cst_alter_land * n, k, ignore_wt);
985 			}
986 			return err == NULL ? (n ? NULL : "")
987 			                   : (*err == 0 ? NOTICE_TILE_FULL : err);
988 		}
989 		else {
990 			// below water level
991 			return "";
992 		}
993 	}
994 	return "Zu nah am Kartenrand";
995 }
996 
997 
check_pos(player_t *,koord3d pos)998 const char *tool_setslope_t::check_pos( player_t *, koord3d pos)
999 {
1000 	grund_t *gr1 = welt->lookup(pos);
1001 	if(gr1) {
1002 		// check for underground mode
1003 		if(  grund_t::underground_mode == grund_t::ugm_all  &&  !gr1->ist_tunnel()  ) {
1004 			return "Terraforming not possible\nhere in underground view";
1005 		}
1006 	}
1007 	else {
1008 		return "";
1009 	}
1010 	return NULL;
1011 }
1012 
check_pos(player_t *,koord3d pos)1013 const char *tool_restoreslope_t::check_pos( player_t *, koord3d pos)
1014 {
1015 	grund_t *gr1 = welt->lookup(pos);
1016 	if(gr1) {
1017 		// check for underground mode
1018 		if(  grund_t::underground_mode == grund_t::ugm_all  &&  !gr1->ist_tunnel()  ) {
1019 			return "Terraforming not possible\nhere in underground view";
1020 		}
1021 	}
1022 	else {
1023 		return "";
1024 	}
1025 	return NULL;
1026 }
1027 
tool_set_slope_work(player_t * player,koord3d pos,int new_slope)1028 const char *tool_setslope_t::tool_set_slope_work( player_t *player, koord3d pos, int new_slope )
1029 {
1030 	if(  !ground_desc_t::double_grounds  ) {
1031 		// translate old single slope parameter to new double slope
1032 		if(  0 < new_slope  &&  new_slope < ALL_UP_SLOPE_SINGLE  ) {
1033 			new_slope = scorner_sw(new_slope) + scorner_se(new_slope) * 3 + scorner_ne(new_slope) * 9 + scorner_nw(new_slope) * 27;
1034 		}
1035 		else {
1036 			switch(  new_slope  ) {
1037 				case ALL_UP_SLOPE:
1038 				case ALL_UP_SLOPE_SINGLE:   new_slope = ALL_UP_SLOPE;   break;
1039 				case ALL_DOWN_SLOPE:
1040 				case ALL_DOWN_SLOPE_SINGLE: new_slope = ALL_DOWN_SLOPE; break;
1041 				case RESTORE_SLOPE:
1042 				case RESTORE_SLOPE_SINGLE:  new_slope = RESTORE_SLOPE;  break;
1043 				default:
1044 					return ""; // invalid parameter
1045 			}
1046 		}
1047 	}
1048 
1049 	bool ok = false;
1050 
1051 	grund_t *gr1 = welt->lookup(pos);
1052 	if(  gr1  ) {
1053 		koord k(pos.get_2d());
1054 
1055 		sint8 water_hgt = welt->get_water_hgt( k );
1056 
1057 		const uint8 max_hdiff = ground_desc_t::double_grounds ?  2 : 1;
1058 
1059 		// at least a pixel away from the border?
1060 		if(  pos.z < water_hgt  &&  !gr1->ist_tunnel()  ) {
1061 			return "Maximum tile height difference reached.";
1062 		}
1063 
1064 		if(  new_slope==RESTORE_SLOPE  &&  !(gr1->get_typ()==grund_t::boden  ||  gr1->get_typ()==grund_t::wasser)  ) {
1065 			return NOTICE_UNSUITABLE_GROUND;
1066 		}
1067 
1068 		// finally: empty enough
1069 		if(  gr1->get_grund_hang()!=gr1->get_weg_hang()  ||  gr1->get_halt().is_bound()  ||  gr1->kann_alle_obj_entfernen(player)  ||
1070 				   gr1->find<gebaeude_t>()  ||  gr1->get_depot()  ||  (gr1->get_leitung() && gr1->hat_wege())  ||  gr1->get_weg(air_wt)  ||  gr1->find<label_t>()  ||  gr1->get_typ()==grund_t::brueckenboden) {
1071 			return NOTICE_TILE_FULL;
1072 		}
1073 
1074 		if(  !welt->is_within_limits(k+koord(1,1))  ||  !welt->is_within_limits(k+koord(-1,-1))) {
1075 			return "Zu nah am Kartenrand";
1076 		}
1077 
1078 		// slopes may affect the position and the total height!
1079 		koord3d new_pos = pos;
1080 
1081 		if(  gr1->hat_wege() || gr1->get_leitung() ) {
1082 			// check the resulting slope
1083 			ribi_t::ribi ribis = 0;
1084 			if( gr1->hat_wege()) {
1085 				ribis |= gr1->get_weg_nr(0)->get_ribi_unmasked();
1086 				if(  gr1->get_weg_nr(1)  ) {
1087 					ribis |= gr1->get_weg_nr(1)->get_ribi_unmasked();
1088 				}
1089 			}
1090 			if( gr1->get_leitung()) {
1091 				ribis |= gr1->get_leitung()->get_ribi();
1092 			}
1093 
1094 			if(  new_slope==RESTORE_SLOPE  ||  !ribi_t::is_single(ribis)  ||  (new_slope<slope_t::raised  &&  ribi_t::backward(ribi_type(new_slope))!=ribis)  ) {
1095 				// has the wrong tilt
1096 				return NOTICE_TILE_FULL;
1097 			}
1098 			// reverse ribis: up to here was direction leaving the tile,
1099 			// now it will be the direction on the tile when moving onto the slope
1100 			ribis = ribi_t::reverse_single(ribis);
1101 			/* new things getting tricky:
1102 			 * A single way on an all up or down slope will result in
1103 			 * a slope with the way as hinge.
1104 			 */
1105 			if(  new_slope==ALL_UP_SLOPE  ) {
1106 				if(  gr1->get_weg_hang()==slope_t::flat  ) {
1107 					new_slope = slope_type(ribis);
1108 				}
1109 				else if(  gr1->get_weg_hang() == slope_type(ribis)  ) {
1110 					// check that way_desc supports such steep slopes
1111 					if(  (gr1->get_weg_nr(0)  &&  !gr1->get_weg_nr(0)->get_desc()->has_double_slopes())
1112 					  ||  (gr1->get_weg_nr(1)  &&  !gr1->get_weg_nr(1)->get_desc()->has_double_slopes())
1113 					  ||  (gr1->get_leitung()  &&  !gr1->get_leitung()->get_desc()->has_double_slopes())  ) {
1114 						return NOTICE_TILE_FULL;
1115 					}
1116 					new_slope = slope_type(ribis) * 2;
1117 				}
1118 				else if(  gr1->get_weg_hang() == slope_type( ribi_t::backward(ribis) ) * 2  ) {
1119 					new_pos.z++;
1120 					if(  welt->lookup(new_pos)  ) {
1121 						return NOTICE_TILE_FULL;
1122 					}
1123 					new_slope = slope_type( ribi_t::backward(ribis) );
1124 				}
1125 				else if(  gr1->get_weg_hang() != slope_type( ribi_t::backward(ribis) )  ) {
1126 					return "Maximum tile height difference reached.";
1127 				}
1128 			}
1129 			else if(  new_slope==ALL_DOWN_SLOPE  ) {
1130 				if(  gr1->get_grund_hang()==slope_type(ribis)  ) {
1131 					// do not lower tiles to sea
1132 					if(  pos.z == water_hgt  &&  !gr1->ist_tunnel()  ) {
1133 						return NOTICE_TILE_FULL;
1134 					}
1135 				}
1136 				else if(  gr1->get_grund_hang() == slope_type(ribis) * 2  ) {
1137 					if(  pos.z == water_hgt  &&  !gr1->ist_tunnel()  ) {
1138 						return NOTICE_TILE_FULL;
1139 					}
1140 					new_slope = slope_type(ribis);
1141 				}
1142 				else if(  gr1->get_grund_hang() == slope_t::flat  ) {
1143 					new_slope = slope_type( ribi_t::backward(ribis) );
1144 					new_pos.z--;
1145 					if(  welt->lookup(new_pos)  ) {
1146 						return NOTICE_TILE_FULL;
1147 					}
1148 				}
1149 				else if(  gr1->get_grund_hang() == slope_type( ribi_t::backward(ribis) )  ) {
1150 					// check that way_desc supports such steep slopes
1151 					if(  (gr1->get_weg_nr(0)  &&  !gr1->get_weg_nr(0)->get_desc()->has_double_slopes())
1152 					  ||  (gr1->get_weg_nr(1)  &&  !gr1->get_weg_nr(1)->get_desc()->has_double_slopes())
1153 					  ||  (gr1->get_leitung()  &&  !gr1->get_leitung()->get_desc()->has_double_slopes())  ) {
1154 						return NOTICE_TILE_FULL;
1155 					}
1156 					new_slope = slope_type( ribi_t::backward(ribis) ) * 2;
1157 					new_pos.z--;
1158 					if(  welt->lookup(new_pos)  ) {
1159 						return NOTICE_TILE_FULL;
1160 					}
1161 				}
1162 				else {
1163 					return "Maximum tile height difference reached.";
1164 				}
1165 			}
1166 		}
1167 
1168 		if(  new_slope == ALL_DOWN_SLOPE  ||  new_slope == RESTORE_SLOPE  ) {
1169 			if(  new_slope == RESTORE_SLOPE  ) {
1170 				// prissi: special action: set to natural slope
1171 				sint8 min_hgt;
1172 				new_slope = welt->recalc_natural_slope( k, min_hgt );
1173 				new_pos = koord3d( k, min_hgt );
1174 				DBG_MESSAGE("natural_slope","%i",new_slope);
1175 			}
1176 			else {
1177 				new_slope = slope_t::flat;
1178 				// is more intuitive: if there is a slope, first downgrade it
1179 				if(  gr1->get_grund_hang() == 0  ) {
1180 					new_pos.z--;
1181 				}
1182 			}
1183 
1184 			// now prevent being lowered below neighbouring water
1185 			sint8 water_table = (water_hgt >= (gr1->get_hoehe() + (gr1->get_grund_hang() ? 1 : 0))) ? water_hgt : welt->get_groundwater() - 4;
1186 			sint8 min_neighbour_height = gr1->get_hoehe();
1187 
1188 			for(  sint16 i = 0 ;  i < 8 ;  i++  ) {
1189 				const koord neighbour = k + koord::neighbours[i];
1190 
1191 				if(  welt->is_within_grid_limits( neighbour )  ) {
1192 					grund_t *gr2 = welt->lookup_kartenboden( neighbour );
1193 					const sint8 water_hgt_neighbour = welt->get_water_hgt( neighbour );
1194 					if(  gr2  &&  (water_hgt_neighbour >= (gr2->get_hoehe() + (gr2->get_grund_hang() ? 1 : 0)))  ) {
1195 						water_table = max( water_table, water_hgt_neighbour );
1196 					}
1197 					if(  gr2  &&  gr2->get_hoehe() < min_neighbour_height  ) {
1198 						min_neighbour_height = gr2->get_hoehe();
1199 					}
1200 				}
1201 			}
1202 
1203 			if(  water_table>new_pos.z  ||  (water_table == new_pos.z  &&  min_neighbour_height < new_pos.z)  ) {
1204 				// do not lower tiles when it will be below water level
1205 				return NOTICE_TILE_FULL;
1206 			}
1207 			welt->set_water_hgt( k, water_table );
1208 			water_hgt = water_table;
1209 		}
1210 		else if(  new_slope == ALL_UP_SLOPE  ) {
1211 			new_slope = slope_t::flat;
1212 			new_pos.z++;
1213 		}
1214 
1215 		// already some ground here (tunnel, bridge, monorail?)
1216 		if(  new_pos.z != pos.z  &&  welt->lookup(new_pos) != NULL  ) {
1217 			return NOTICE_TILE_FULL;
1218 		}
1219 		// check for grounds above / below
1220 		if(  new_pos.z >= pos.z  ) {
1221 			grund_t *gr2 = welt->lookup( new_pos + koord3d(0, 0, 1) );
1222 			if(  !gr2  ) {
1223 				gr2 = welt->lookup( new_pos + koord3d(0, 0, 2) );
1224 			}
1225 			if(  !gr2  &&  welt->get_settings().get_way_height_clearance()==2  &&  (gr1->hat_wege()  ||  gr1->get_leitung())  ) {
1226 				gr2 = welt->lookup( new_pos + koord3d(0, 0, 3) );
1227 			}
1228 			// slope may alter amount of clearance required
1229 			if(  gr2  &&  gr2->get_pos().z - new_pos.z + slope_t::min_diff( gr2->get_weg_hang(), new_slope ) < welt->get_settings().get_way_height_clearance()  ) {
1230 				return NOTICE_TILE_FULL;
1231 			}
1232 		}
1233 		if(  new_pos.z <= pos.z  ) {
1234 			grund_t *gr2 = welt->lookup( new_pos + koord3d(0, 0, -1) );
1235 			if(  !gr2  ) {
1236 				gr2 = welt->lookup( new_pos + koord3d(0, 0, -2) );
1237 			}
1238 			if(  !gr2  &&  welt->get_settings().get_way_height_clearance()==2  ) {
1239 				gr2 = welt->lookup( new_pos + koord3d(0, 0, -3) );
1240 			}
1241 			// slope may alter amount of clearance required
1242 			if(  gr2  &&  new_pos.z - gr2->get_pos().z + slope_t::min_diff( new_slope, gr2->get_weg_hang() ) < welt->get_settings().get_way_height_clearance()  ) {
1243 				return NOTICE_TILE_FULL;
1244 			}
1245 		}
1246 
1247 		// check, if action is valid ...
1248 		const sint16 hgt=new_pos.z;
1249 		// maximum difference check with tiles to north, south east and west
1250 		const sint8 test_hgt = hgt+(new_slope!=0);
1251 
1252 		if(  gr1->get_typ()==grund_t::boden  ) {
1253 			for(  sint16 i = 0 ;  i < 4 ;  i++  ) {
1254 				const koord neighbour = k + koord::nsew[i];
1255 
1256 				const grund_t *gr_neighbour=welt->lookup_kartenboden(neighbour);
1257 				if(gr_neighbour) {
1258 					const sint16 gr_neighbour_hgt=gr_neighbour->get_hoehe() + (new_slope==ALL_DOWN_SLOPE && gr_neighbour->get_grund_hang()? 1 : 0);
1259 					const sint8 diff_from_ground = abs(gr_neighbour_hgt-test_hgt);
1260 					if(  diff_from_ground > 2 * max_hdiff  ) {
1261 						return "Maximum tile height difference reached.";
1262 					}
1263 				}
1264 			}
1265 		}
1266 
1267 		// ok, now we set the slope ...
1268 		ok = (new_pos!=pos);
1269 		bool slope_changed = new_slope!=gr1->get_grund_hang();
1270 		ok |= slope_changed;
1271 
1272 		if(ok) {
1273 			// check if clear
1274 			if(  gr1->kann_alle_obj_entfernen(player)  ) {
1275 				return NOTICE_TILE_FULL;
1276 			}
1277 
1278 			// check way ownership
1279 			if(gr1->hat_wege()) {
1280 				if(gr1->get_weg_nr(0)->is_deletable(player)!=NULL) {
1281 					return NOTICE_TILE_FULL;
1282 				}
1283 				if(gr1->has_two_ways()  &&  gr1->get_weg_nr(1)->is_deletable(player)!=NULL) {
1284 					return NOTICE_TILE_FULL;
1285 				}
1286 			}
1287 
1288 			// check funds
1289 			settings_t const& s = welt->get_settings();
1290 			sint64 const cost = new_slope == RESTORE_SLOPE ? s.cst_alter_land : s.cst_set_slope;
1291 			if(  !player->can_afford(cost)  ) {
1292 				return NOTICE_INSUFFICIENT_FUNDS;
1293 			}
1294 
1295 			// ok, it was a success
1296 			if(  !gr1->is_water()  &&  new_slope == 0  &&  hgt == water_hgt  &&  gr1->get_typ() != grund_t::tunnelboden  ) {
1297 				// now water
1298 				gr1->obj_loesche_alle(player);
1299 				welt->access(k)->kartenboden_setzen( new wasser_t(new_pos) );
1300 				gr1 = welt->lookup_kartenboden(k);
1301 			}
1302 			else if(  gr1->is_water()  &&  (new_pos.z > water_hgt  ||  new_slope != 0)  ) {
1303 				// build underwater hill first
1304 				if(  !welt->flatten_tile( player, k, water_hgt, false, true )  ) {
1305 					return NOTICE_TILE_FULL;
1306 				}
1307 				gr1->obj_loesche_alle(player);
1308 				welt->access(k)->kartenboden_setzen( new boden_t(new_pos,new_slope) );
1309 				gr1 = welt->lookup_kartenboden(k);
1310 				welt->set_water_hgt(k, welt->get_groundwater()-4);
1311 			}
1312 			else {
1313 				gr1->set_grund_hang(new_slope);
1314 				gr1->set_pos(new_pos);
1315 				gr1->clear_flag(grund_t::marked);
1316 				gr1->set_flag(grund_t::dirty);
1317 				// update new positions if changed
1318 				if(  new_pos!=pos  ) {
1319 					for(  int i=0;  i<gr1->get_top();  i++  ) {
1320 						gr1->obj_bei(i)->set_pos( new_pos );
1321 					}
1322 				}
1323 				// correct tree offsets if slope has changed
1324 				if(  slope_changed  ) {
1325 					for(  int i=0;  i<gr1->get_top();  i++  ) {
1326 						baum_t *tree = obj_cast<baum_t>(gr1->obj_bei(i));
1327 						if (tree) {
1328 							tree->recalc_off();
1329 						}
1330 					}
1331 				}
1332 				if(  !gr1->ist_karten_boden()  ) {
1333 					gr1->calc_image();
1334 				}
1335 			}
1336 
1337 			// if there is a powerline here we need to treat it as newly built as it may connect to neighbours
1338 			leitung_t *lt = gr1->get_leitung();
1339 			if(  lt  ) {
1340 				// remove maintenance for existing powerline
1341 				player_t::add_maintenance(lt->get_owner(), -lt->get_desc()->get_maintenance(), powerline_wt);
1342 				lt->finish_rd();
1343 			}
1344 
1345 			if(  gr1->ist_karten_boden()  ) {
1346 				if(  new_slope!=slope_t::flat  ) {
1347 					// no lakes on slopes ...
1348 					groundobj_t *obj = gr1->find<groundobj_t>();
1349 					if(  obj  &&  obj->get_desc()->get_phases()!=16  ) {
1350 						obj->cleanup(player);
1351 						delete obj;
1352 					}
1353 					// connect canals to sea
1354 					if(  gr1->get_hoehe() == water_hgt  &&  gr1->hat_weg(water_wt)  ) {
1355 						grund_t *sea = welt->lookup_kartenboden(k - koord( ribi_type(new_slope ) ));
1356 						if (sea  &&  sea->is_water()) {
1357 							gr1->weg_erweitern(water_wt, ribi_t::backward(ribi_type(new_slope)));
1358 							sea->calc_image();
1359 						}
1360 					}
1361 				}
1362 				// recalc slope walls on neighbours
1363 				for(int y=-1; y<=1; y++) {
1364 					for(int x=-1; x<=1; x++) {
1365 						grund_t *gr = welt->lookup_kartenboden(k+koord(x,y));
1366 						gr->calc_image();
1367 					}
1368 				}
1369 				// correct the grid height
1370 				if(  gr1->is_water()  ) {
1371 					sint8 grid_hgt = min( water_hgt, welt->lookup_hgt( k ) );
1372 					welt->set_grid_hgt(k, grid_hgt );
1373 				}
1374 				else {
1375 					welt->set_grid_hgt(k, gr1->get_hoehe()+ corner_nw(gr1->get_grund_hang()) );
1376 				}
1377 				minimap_t::get_instance()->calc_map_pixel(k);
1378 
1379 				welt->calc_climate( k, true );
1380 			}
1381 			player_t::book_construction_costs(player, cost, k, ignore_wt);
1382 		}
1383 		// update limits
1384 		if(  welt->min_height > gr1->get_hoehe()  ) {
1385 			welt->min_height = gr1->get_hoehe();
1386 		}
1387 		else if(  welt->max_height < gr1->get_hoehe()  ) {
1388 			welt->max_height = gr1->get_hoehe();
1389 		}
1390 	}
1391 	return ok ? NULL : "";
1392 }
1393 
1394 
1395 
1396 // set marker
work(player_t * player,koord3d pos)1397 const char *tool_marker_t::work( player_t *player, koord3d pos )
1398 {
1399 	grund_t *gr = welt->lookup_kartenboden(pos.get_2d());
1400 	if (gr) {
1401 		if(!gr->get_text()) {
1402 			const obj_t* thing = gr->obj_bei(0);
1403 			if(thing == NULL  ||  thing->get_owner() == player  ||  (player_t::check_owner(thing->get_owner(), player)  &&  (thing->get_typ() != obj_t::gebaeude))) {
1404 				gr->obj_add(new label_t(gr->get_pos(), player, default_param ? default_param : "\0"));
1405 				if (can_use_gui()) {
1406 					gr->find<label_t>()->show_info();
1407 				}
1408 				return NULL;
1409 			}
1410 		}
1411 	}
1412 	return "Das Feld gehoert\neinem anderen Spieler\n";
1413 }
1414 
1415 
1416 
1417 // show/repair blocks
init(player_t *)1418 bool tool_clear_reservation_t::init( player_t * )
1419 {
1420 	if (can_use_gui()) {
1421 		schiene_t::show_reservations = true;
1422 		welt->set_dirty();
1423 	}
1424 	return true;
1425 }
1426 
exit(player_t *)1427 bool tool_clear_reservation_t::exit( player_t * )
1428 {
1429 	if (can_use_gui()) {
1430 		schiene_t::show_reservations = false;
1431 		welt->set_dirty();
1432 	}
1433 	return true;
1434 }
1435 
work(player_t *,koord3d pos)1436 const char *tool_clear_reservation_t::work( player_t *, koord3d pos )
1437 {
1438 	grund_t *gr = welt->lookup(pos);
1439 	if(gr) {
1440 		for(unsigned wnr=0;  wnr<2;  wnr++  ) {
1441 
1442 			schiene_t const* const w = obj_cast<schiene_t>(gr->get_weg_nr(wnr));
1443 			// is this a reserved track?
1444 			if(w!=NULL  &&  w->is_reserved()) {
1445 				/* now we do a very crude procedure:
1446 				 * - we search all ways for reservations of this convoi and remove them
1447 				 * - we set the convoi state to ROUTING_1; it must reserve again its ways then
1448 				 */
1449 				const waytype_t waytype = w->get_waytype();
1450 				const convoihandle_t cnv = w->get_reserved_convoi();
1451 				if(cnv->get_state()==convoi_t::DRIVING) {
1452 					// reset driving state
1453 					cnv->suche_neue_route();
1454 				}
1455 				FOR(slist_tpl<weg_t*>, const w, weg_t::get_alle_wege()) {
1456 					if (w->get_waytype() == waytype) {
1457 						schiene_t* const sch = obj_cast<schiene_t>(w);
1458 						if (sch->get_reserved_convoi() == cnv) {
1459 							vehicle_t& v = *cnv->front();
1460 							if (!gr->suche_obj(v.get_typ())) {
1461 								// force free
1462 								sch->unreserve(&v);
1463 							}
1464 						}
1465 					}
1466 				}
1467 			}
1468 		}
1469 	}
1470 	return NULL;
1471 }
1472 
1473 
1474 // transformer for electricity supply
get_tooltip(const player_t *) const1475 const char* tool_transformer_t::get_tooltip(const player_t *) const
1476 {
1477 	settings_t const& s = welt->get_settings();
1478 	sprintf(toolstr, "%s, %ld$ (%ld$)", translator::translate("Build drain"), (long)(s.cst_transformer / -100), (long)(welt->scale_with_month_length(s.cst_maintain_transformer)) / -100);
1479 	return toolstr;
1480 }
1481 
get_icon(player_t *) const1482 image_id tool_transformer_t::get_icon(player_t*) const
1483 {
1484 	return way_builder_t::waytype_available( powerline_wt, welt->get_timeline_year_month() ) ? icon : IMG_EMPTY;
1485 }
1486 
init(player_t *)1487 bool tool_transformer_t::init( player_t *)
1488 {
1489 	return way_builder_t::waytype_available( powerline_wt, welt->get_timeline_year_month() );
1490 }
1491 
1492 
check_pos(player_t *,koord3d pos)1493 const char *tool_transformer_t::check_pos( player_t *, koord3d pos )
1494 {
1495 	if(grund_t::underground_mode == grund_t::ugm_all  &&  env_t::networkmode) {
1496 		// clients cannot guess at which height transformer should be build
1497 		return "Cannot built this station/building\nin underground mode here.";
1498 	}
1499 	if(grund_t::underground_mode == grund_t::ugm_level) {
1500 		// only above or directly under surface
1501 		// taking into account way clearance requirements
1502 		grund_t *gr = welt->lookup_kartenboden(pos.get_2d());
1503 		return (gr->get_pos() == pos  ||  gr->get_hoehe() == grund_t::underground_level + welt->get_settings().get_way_height_clearance()) ? NULL : "";
1504 	}
1505 	return NULL;
1506 }
1507 
1508 
work(player_t * player,koord3d pos)1509 const char *tool_transformer_t::work( player_t *player, koord3d pos )
1510 {
1511 	DBG_MESSAGE("tool_transformer_t()","called on %d,%d", pos.x, pos.y);
1512 
1513 	koord k(pos.get_2d());
1514 
1515 	grund_t *gr = welt->lookup_kartenboden(k);
1516 	if(  !welt->get_settings().get_allow_underground_transformers()  &&  pos.z!=gr->get_hoehe()  ) {
1517 		// no underground transformers allowed
1518 		return "Cannot built this station/building\nin underground mode here.";
1519 	}
1520 
1521 	bool underground = false;
1522 	fabrik_t *fab = NULL;
1523 	// full underground mode: coordinate is on ground, adjust it to one level below ground
1524 	// not possible in network mode!
1525 	if (!env_t::networkmode  &&  grund_t::underground_mode == grund_t::ugm_all) {
1526 		pos = gr->get_pos() - koord3d( 0, 0, welt->get_settings().get_way_height_clearance() );
1527 	}
1528 	// search for factory
1529 	// must be independent of network mode
1530 	if (gr->get_pos().z <= pos.z) {
1531 		fab = leitung_t::suche_fab_4(k);
1532 	}
1533 	else if(  gr->get_pos().z == pos.z+welt->get_settings().get_way_height_clearance()  ) {
1534 		fab = fabrik_t::get_fab( k);
1535 		underground = true;
1536 	}
1537 
1538 	if( !fab  ) {
1539 		return "Transformer only next to factory!";
1540 	}
1541 	if(  fab->is_transformer_connected()  ) {
1542 		return "Only one transformer per factory!";
1543 	}
1544 
1545 	// underground: first build tunnel tile	at coordinate pos
1546 	if(underground) {
1547 		if(gr->is_water()) {
1548 			return "Transformer only next to factory!";
1549 		}
1550 
1551 		if(welt->lookup(pos)) {
1552 			return NOTICE_TILE_FULL;
1553 		}
1554 
1555 		if(  welt->get_settings().get_way_height_clearance()==2  &&  welt->lookup(pos + koord3d( 0, 0, 1 ))  ) {
1556 			return NOTICE_TILE_FULL;
1557 		}
1558 
1559 		const tunnel_desc_t *tunnel_desc = tunnel_builder_t::get_tunnel_desc(powerline_wt, 0, 0);
1560 		if(  tunnel_desc==NULL  ) {
1561 			return "Cannot built this station/building\nin underground mode here.";
1562 		}
1563 
1564 		tunnelboden_t* tunnel = new tunnelboden_t(pos, 0);
1565 		welt->access(k)->boden_hinzufuegen(tunnel);
1566 		tunnel->obj_add(new tunnel_t(pos, player, tunnel_desc));
1567 		player_t::add_maintenance( player, tunnel_desc->get_maintenance(), tunnel_desc->get_finance_waytype() );
1568 		gr = tunnel;
1569 	}
1570 	else {
1571 		// above ground: check for clear tile
1572 		if(gr->get_grund_hang()!=0  ||  !gr->ist_natur()) {
1573 			return "Transformer only on flat bare land!";
1574 		}
1575 		// remove everything on that spot
1576 		if(const char *fail = gr->kann_alle_obj_entfernen(player)) {
1577 			return fail;
1578 		}
1579 		gr->obj_loesche_alle(player);
1580 	}
1581 	// transformer will be build on tile pointed to by gr
1582 
1583 	// build source or drain depending on factory type
1584 	if(fab->get_desc()->is_electricity_producer()) {
1585 		pumpe_t *p = new pumpe_t(gr->get_pos(), player);
1586 		gr->obj_add( p );
1587 		p->finish_rd();
1588 	}
1589 	else {
1590 		senke_t *s = new senke_t(gr->get_pos(), player);
1591 		gr->obj_add(s);
1592 		s->finish_rd();
1593 	}
1594 
1595 	return NULL;	// ok
1596 }
1597 
1598 
1599 
1600 /**
1601  * found a new city
1602  * @author Hj. Malthaner
1603  */
work(player_t * player,koord3d pos)1604 const char *tool_add_city_t::work( player_t *player, koord3d pos )
1605 {
1606 	// check funds
1607 	const sint64 cost = welt->get_settings().cst_found_city;
1608 	if(  !player->can_afford(cost)  ) {
1609 		return NOTICE_INSUFFICIENT_FUNDS;
1610 	}
1611 
1612 	koord k(pos.get_2d());
1613 
1614 	grund_t *gr = welt->lookup_kartenboden(k);
1615 	if(gr) {
1616 		if(gr->ist_natur() &&
1617 			!gr->is_water() &&
1618 			gr->get_grund_hang() == 0  &&
1619 			hausbauer_t::get_special( 0, building_desc_t::townhall, welt->get_timeline_year_month(), 0, welt->get_climate( k ) ) != NULL  ) {
1620 
1621 			gebaeude_t const* const gb = obj_cast<gebaeude_t>(gr->first_obj());
1622 			if(gb && gb->is_townhall()) {
1623 				dbg->warning("tool_add_city()", "Already a city here");
1624 				return NOTICE_TILE_FULL;
1625 			}
1626 			else {
1627 
1628 				// Hajo: if city is owned by player and player removes special
1629 				// buildings the game crashes. To avoid this problem cities
1630 				// always belong to player 1
1631 
1632 				int const citizens = (int)(welt->get_settings().get_mean_citizen_count() * 0.9);
1633 				//  stadt_t *stadt = new stadt_t(welt->get_public_player(), pos,citizens/10+simrand(2*citizens+1));
1634 
1635 				// always start with 1/10 citizens
1636 				stadt_t* stadt = new stadt_t(welt->get_public_player(), k, citizens / 10);
1637 				if (stadt->get_buildings() == 0) {
1638 					delete stadt;
1639 					return NOTICE_UNSUITABLE_GROUND;
1640 				}
1641 
1642 				welt->add_city(stadt);
1643 				stadt->finish_rd();
1644 				stadt->verbinde_fabriken();
1645 
1646 				player_t::book_construction_costs(player, cost, k, ignore_wt);
1647 				minimap_t::get_instance()->calc_map();
1648 				return NULL;
1649 			}
1650 		}
1651 		else {
1652 			return NOTICE_UNSUITABLE_GROUND;
1653 		}
1654 	}
1655 	return "";
1656 }
1657 
1658 // buy a house
work(player_t * player,koord3d pos)1659 const char *tool_buy_house_t::work( player_t *player, koord3d pos)
1660 {
1661 	if ( player == welt->get_public_player() ) {
1662 		return "";
1663 	}
1664 	grund_t* gr = welt->lookup_kartenboden(pos.get_2d());
1665 	if(!gr  ||  gr->hat_wege()  ||  gr->get_halt().is_bound()) {
1666 		return "";
1667 	}
1668 
1669 	// since buildings can have more than one tile, we must handle them together
1670 	gebaeude_t* gb = gr->find<gebaeude_t>();
1671 	if(  gb== NULL  ||  !gb->is_city_building()  ||  !player_t::check_owner(gb->get_owner(),player)  ) {
1672 		return "Das Feld gehoert\neinem anderen Spieler\n";
1673 	}
1674 
1675 	if(  gb->get_owner()==player  ) {
1676 		// I bought this already ...
1677 		return "";
1678 	}
1679 
1680 	player_t *old_owner = gb->get_owner();
1681 	const building_tile_desc_t *tile  = gb->get_tile();
1682 	const building_desc_t * bdsc = tile->get_desc();
1683 	koord size = bdsc->get_size( tile->get_layout() );
1684 
1685 	koord k;
1686 	for(k.y = 0; k.y < size.y; k.y ++) {
1687 		for(k.x = 0; k.x < size.x; k.x ++) {
1688 			grund_t *gr = welt->lookup(koord3d(k,0)+pos);
1689 			if(gr) {
1690 				gebaeude_t *gb_part = gr->find<gebaeude_t>();
1691 				// there may be buildings with holes
1692 				if(  gb_part  &&  gb_part->get_tile()->get_desc()==bdsc  &&  player_t::check_owner(gb_part->get_owner(),player)  ) {
1693 					sint32 const maint = welt->get_settings().maint_building * bdsc->get_level();
1694 					player_t::add_maintenance(old_owner, -maint, gb->get_waytype());
1695 					player_t::add_maintenance(player,        +maint, gb->get_waytype());
1696 					gb->set_owner(player);
1697 					player_t::book_construction_costs(player, -maint, k + pos.get_2d(), gb->get_waytype());
1698 				}
1699 			}
1700 		}
1701 	}
1702 	return NULL;
1703 }
1704 
1705 /* change city size
1706  * @author prissi
1707  */
init(player_t *)1708 bool tool_change_city_size_t::init( player_t * )
1709 {
1710 	cursor = atoi(default_param)>0 ? tool_t::general_tool[TOOL_RAISE_LAND]->cursor : tool_t::general_tool[TOOL_LOWER_LAND]->cursor;
1711 	return true;
1712 }
1713 
work(player_t *,koord3d pos)1714 const char *tool_change_city_size_t::work( player_t *, koord3d pos )
1715 {
1716 	stadt_t *city = welt->find_nearest_city(pos.get_2d());
1717 	if(city!=NULL) {
1718 		city->change_size( atoi(default_param) );
1719 		// Knightly : update the links from other cities to this city
1720 		FOR(weighted_vector_tpl<stadt_t*>, const c, welt->get_cities()) {
1721 			c->remove_target_city(city);
1722 			c->add_target_city(city);
1723 		}
1724 		return NULL;
1725 	}
1726 	return "";
1727 }
1728 
1729 
1730 /* change climate
1731  * @author kieron
1732  */
get_tooltip(player_t const *) const1733 const char *tool_set_climate_t::get_tooltip(player_t const*) const
1734 {
1735 	char temp[1024];
1736 	sprintf( temp, translator::translate( "Set tile climate" ), translator::translate( ground_desc_t::get_climate_name_from_bit((climate)atoi(default_param)) ) );
1737 	return tooltip_with_price( temp,  welt->get_settings().cst_alter_climate );
1738 }
1739 
is_valid_pos(player_t * player,const koord3d &,const char * & error,const koord3d &)1740 uint8 tool_set_climate_t::is_valid_pos(player_t *player, const koord3d &, const char *& error, const koord3d &)
1741 {
1742 	error = NULL;
1743 	// no dragging in networkmode but for admin
1744 	return env_t::networkmode  &&  !player->is_public_service()  ?  1 /*no dragging*/ :  2 /*dragging allowed*/;
1745 }
1746 
mark_tiles(player_t *,const koord3d & start,const koord3d & end)1747 void tool_set_climate_t::mark_tiles(player_t *, const koord3d &start, const koord3d &end)
1748 {
1749 	koord k1, k2;
1750 	k1.x = start.x < end.x ? start.x : end.x;
1751 	k1.y = start.y < end.y ? start.y : end.y;
1752 	k2.x = start.x + end.x - k1.x;
1753 	k2.y = start.y + end.y - k1.y;
1754 	koord k;
1755 	for(  k.x = k1.x;  k.x <= k2.x;  k.x++  ) {
1756 		for(  k.y = k1.y;  k.y <= k2.y;  k.y++  ) {
1757 			grund_t *gr = welt->lookup_kartenboden( k );
1758 
1759 			zeiger_t *marker = new zeiger_t(gr->get_pos(), NULL );
1760 
1761 			const uint8 grund_hang = gr->get_grund_hang();
1762 			const uint8 weg_hang = gr->get_weg_hang();
1763 			const uint8 hang = max( corner_sw(grund_hang), corner_sw(weg_hang) ) + 3 * max( corner_se(grund_hang), corner_se(weg_hang) ) + 9 * max( corner_ne(grund_hang), corner_ne(weg_hang) ) + 27 * max( corner_nw(grund_hang), corner_nw(weg_hang) );
1764 			uint8 back_hang = (hang % 3) + 3 * ((uint8)(hang / 9)) + 27;
1765 			marker->set_foreground_image( ground_desc_t::marker->get_image( grund_hang % 27 ) );
1766 			marker->set_image( ground_desc_t::marker->get_image( back_hang ) );
1767 
1768 			marker->mark_image_dirty( marker->get_image(), 0 );
1769 			gr->obj_add( marker );
1770 			marked.insert( marker );
1771 		}
1772 	}
1773 }
1774 
1775 
do_work(player_t * player,const koord3d & start,const koord3d & end)1776 const char *tool_set_climate_t::do_work( player_t *player, const koord3d &start, const koord3d &end )
1777 {
1778 	int n = 0;	// tiles altered
1779 	climate cl = (climate) atoi(default_param);
1780 	koord k1, k2;
1781 	if(  end == koord3d::invalid  ) {
1782 		k1.x = k2.x = start.x;
1783 		k1.y = k2.y = start.y;
1784 	}
1785 	else {
1786 		k1.x = start.x < end.x ? start.x : end.x;
1787 		k1.y = start.y < end.y ? start.y : end.y;
1788 		k2.x = start.x + end.x - k1.x;
1789 		k2.y = start.y + end.y - k1.y;
1790 	}
1791 	koord k;
1792 	for(  k.x = k1.x;  k.x <= k2.x;  k.x++  ) {
1793 		for(  k.y = k1.y;  k.y <= k2.y;  k.y++  ) {
1794 			if(  grund_t *gr=welt->lookup_kartenboden(k)  ) {
1795 				if(  cl != water_climate  ) {
1796 					bool ok = true;
1797 					if(  gr->is_water()  ) {
1798 						const sint8 hgt = welt->lookup_hgt(k);
1799 						ok = welt->get_water_hgt(k) == hgt  &&  welt->is_plan_height_changeable( k.x, k.y );
1800 						// check s, se, e - these must not be deep water!
1801 						for(  int i = 3 ;  i < 6 && ok ;  i++  ) {
1802 							koord k_neighbour(k + koord::neighbours[i]);
1803 							if(  welt->is_within_grid_limits(k_neighbour)  ) {
1804 								ok = welt->lookup_hgt(k_neighbour) >= hgt;
1805 							}
1806 						}
1807 						if(  ok  ) {
1808 							gr->obj_loesche_alle( NULL );
1809 							welt->set_water_hgt( k, hgt - 1 );
1810 							welt->access(k)->correct_water();
1811 						}
1812 					}
1813 					if(  ok  ) {
1814 						welt->set_climate( k, cl, true );
1815 						minimap_t::get_instance()->calc_map_pixel( k );
1816 						n ++;
1817 					}
1818 				}
1819 				else if(  !gr->is_water()  &&  gr->get_grund_hang() == slope_t::flat  &&  welt->is_plan_height_changeable( k.x, k.y )  ) {
1820 					bool ok = true;
1821 					for(  int i = 0 ;  i < 8;  i++  ) {
1822 						grund_t *gr2 = welt->lookup_kartenboden( k + koord::neighbours[i] );
1823 						if(  gr2  &&  ok  ) {
1824 							ok = gr2->get_pos().z >= gr->get_pos().z;
1825 						}
1826 					}
1827 					if(  ok  ) {
1828 						gr->obj_loesche_alle( NULL );
1829 						welt->set_water_hgt( k, gr->get_pos().z );
1830 						welt->access(k)->correct_water();
1831 						welt->set_climate( k, water_climate, true );
1832 						minimap_t::get_instance()->calc_map_pixel( k );
1833 						n ++;
1834 					}
1835 				}
1836 
1837 			}
1838 		}
1839 	}
1840 	if(n>0) {
1841 		player_t::book_construction_costs(player, welt->get_settings().cst_alter_climate * n, k, ignore_wt);
1842 	}
1843 	return NULL;
1844 }
1845 
1846 
1847 /* change water height
1848  * @author kieron
1849  */
init(player_t * player)1850 bool tool_change_water_height_t::init( player_t *player )
1851 {
1852 	cursor = atoi(default_param) > 0 ? tool_t::general_tool[TOOL_RAISE_LAND]->cursor : tool_t::general_tool[TOOL_LOWER_LAND]->cursor;
1853 	return !env_t::networkmode  ||  player->is_public_service();
1854 }
1855 
1856 
work(player_t *,koord3d pos)1857 const char *tool_change_water_height_t::work( player_t *, koord3d pos )
1858 {
1859 	if(  pos == koord3d::invalid  ) {
1860 		return "Cannot alter water";
1861 	}
1862 
1863 	// calculate new height to use:
1864 	bool raising = atoi(default_param) > 0;
1865 	koord k = pos.get_2d();
1866 	sint8 new_water_height;
1867 	grund_t *gr = welt->lookup_kartenboden(k);
1868 
1869 	if(  gr->is_water()  ) {
1870 		// lower + control removes shallow water only. If this tile is deep water this will fail
1871 		if(  !raising  &&  is_ctrl_pressed()  &&  welt->min_hgt(k)!=gr->get_hoehe()  ) {
1872 			return "Cannot alter water";
1873 		}
1874 
1875 		// if currently water, raise = +1, lower = -1
1876 		new_water_height = gr->get_hoehe() + (raising ? 1 : -1);
1877 	}
1878 	// if not water then raise = set water height to ground height, lower = error
1879 	else if(  raising  ) {
1880 		slope_t::type slope = gr->get_grund_hang();
1881 		new_water_height = gr->get_hoehe() + max( max( corner_sw(slope), corner_se(slope) ),max( corner_ne(slope), corner_nw(slope) ) );
1882 	}
1883 	else {
1884 		return "Cannot alter water";
1885 	}
1886 	if(  new_water_height < welt->get_groundwater() - 3  ) {
1887 		return "Cannot alter water";
1888 	}
1889 	sint8 test_height = max( new_water_height, gr->get_hoehe() );
1890 
1891 	// make a list of tiles to change
1892 	// cannot use a recursive method as stack is not large enough!
1893 
1894 	sint8 *from_dir = new sint8[welt->get_size().x * welt->get_size().y];
1895 	sint8 *stage = new sint8[welt->get_size().x * welt->get_size().y];
1896 	memset( from_dir, -1, sizeof(sint8) * welt->get_size().x * welt->get_size().y );
1897 	memset( stage, -1, sizeof(sint8) * welt->get_size().x * welt->get_size().y );
1898 #define array_koord(px,py) (px + py * welt->get_size().x)
1899 	stage[array_koord(k.x,k.y)]=0;
1900 	do {
1901 		// firstly we must be able to change ground height
1902 		bool ok = welt->is_plan_height_changeable( k.x, k.y )  &&  k.x > 0  &&  k.y > 0  &&  k.x < welt->get_size().x - 1  &&  k.y < welt->get_size().y - 1;
1903 		const planquadrat_t *plan = welt->access(k);
1904 
1905 		// next there cannot be any grounds directly above this tile
1906 		sint8 h = plan->get_kartenboden()->get_hoehe() + 1;
1907 		while(  ok  &&  h < new_water_height + welt->get_settings().get_way_height_clearance()  ) {
1908 			if(  plan->get_boden_in_hoehe(h)  ) {
1909 				ok = false;
1910 			}
1911 			h++;
1912 		}
1913 
1914 		if(  !ok  ) {
1915 			delete [] from_dir;
1916 			delete [] stage;
1917 			return "Cannot alter water";
1918 		}
1919 
1920 		// get neighbour corner heights
1921 		sint8 neighbour_heights[8][4];
1922 		welt->get_neighbour_heights( k, neighbour_heights );
1923 
1924 		for(  int i = stage[array_koord(k.x,k.y)];  i < 8;  i++  ) {
1925 			koord k_neighbour = k + koord::neighbours[i];
1926 			grund_t *gr2 = welt->lookup_kartenboden(k_neighbour);
1927 			if(  gr2  ) {
1928 				sint8 neighbour_height = gr2->get_hoehe();
1929 
1930 				// move onto this tile if it hasn't been processed yet
1931 				bool ok = stage[array_koord(k_neighbour.x, k_neighbour.y)] == -1;
1932 
1933 				if(  raising  ) {
1934 					// test whether points adjacent to current tile will be flooded
1935 					// if control key modifier pressed, level ground will be left alone, but then need to check for spills
1936 
1937 					// for neighbour i test corners adjacent to tile
1938 					// nw (i = 0), test se (corner 1)
1939 					// w (i = 1), test se (corner 1) and ne (corner 2)
1940 					// sw (i = 2), test ne (corner 2)
1941 					// s (i = 3), test ne (corner 2) and nw (corner 3)
1942 					// se (i = 4), test nw (corner 3)
1943 					// e (i = 5), test nw (corner 3) and sw (corner 0)
1944 					// ne (i = 6), test sw (corner 0)
1945 					// n (i = 7), test sw (corner 0) and se (corner 1)
1946 
1947 					if(  is_ctrl_pressed()  ) {
1948 						ok = ok  &&  ( (gr2->get_grund_hang()!=slope_t::flat  &&  welt->max_hgt(k_neighbour) <= test_height) ||
1949 							neighbour_heights[i][((i >> 1) + 1) & 3] < test_height ||
1950 							( (i & 1)  &&  neighbour_heights[i][((i >> 1) + 2) & 3] < test_height) );
1951 					}
1952 					else {
1953 						ok = ok  &&  (neighbour_heights[i][((i >> 1) + 1) & 3] <= test_height ||
1954 							( (i & 1)  &&  neighbour_heights[i][((i >> 1) + 2) & 3] <= test_height));
1955 					}
1956 
1957 					// move onto this tile unless it already has water at new level, or the land level is above new level
1958 					ok = ok  &&  welt->get_water_hgt(k_neighbour) < new_water_height;
1959 				}
1960 				else {
1961 					if(  is_ctrl_pressed()  ) {
1962 						ok = ok  &&  welt->min_hgt(k_neighbour) == test_height;
1963 					}
1964 					else {
1965 						ok = ok  &&  neighbour_height <= test_height;
1966 					}
1967 
1968 					// move onto this tile unless it already has water at new level, or the land level is above new level
1969 					ok = ok  &&  welt->get_water_hgt(k_neighbour) > new_water_height;
1970 				}
1971 
1972 				if(  ok  ) {
1973 					//move on to next tile
1974 					from_dir[array_koord(k_neighbour.x,k_neighbour.y)] = i;
1975 					stage[array_koord(k_neighbour.x,k_neighbour.y)] = 0;
1976 					stage[array_koord(k.x,k.y)] = i;
1977 					k = k_neighbour;
1978 					break;
1979 				}
1980 			}
1981 			//return back to previous tile
1982 			if(  i==7  ) {
1983 				stage[array_koord(k.x,k.y)] = 8;
1984 				if(  from_dir[array_koord(k.x,k.y)] != -1  ) {
1985 					k = k - koord::neighbours[from_dir[array_koord(k.x,k.y)]];
1986 				}
1987 			}
1988 		}
1989 	} while(  from_dir[array_koord(k.x,k.y)] != -1  ||  stage[array_koord(k.x,k.y)] < 7  );
1990 
1991 	delete [] from_dir;
1992 
1993 	// loop over map to find marked tiles
1994 	for(  int y = 1;  y<welt->get_size().y - 1;  y++  ) {
1995 		for(  int x = 1;  x<welt->get_size().x - 1;  x++  ) {
1996 			if(  stage[array_koord(x,y)] > -1  ) {
1997 				// calculate new height, slope and climate and set water height
1998 				grund_t *gr2 =welt->lookup_kartenboden(x, y);
1999 
2000 				// remove any objects on this tile
2001 				gr2->obj_loesche_alle( NULL );
2002 
2003 				const sint8 h0 = gr2->get_hoehe();
2004 				const sint8 min_grid_hgt = welt->min_hgt( koord( x, y ) );
2005 
2006 				sint8 h0_nw, h0_ne, h0_se, h0_sw;
2007 
2008 				if(  gr2->is_water()  ) {
2009 					// water - maximum existing height can be is old water height no matter what surrounding grids are
2010 					h0_nw = min(h0, welt->lookup_hgt(x, y));
2011 					h0_ne = min(h0, welt->lookup_hgt(x+1, y));
2012 					h0_se = min(h0, welt->lookup_hgt(x+1, y+1));
2013 					h0_sw = min(h0, welt->lookup_hgt(x, y+1));
2014 				}
2015 				else if(  h0 > min_grid_hgt  ) {
2016 					// if min grid height here is less than ground height it will be because we are partially water
2017 					h0_nw = welt->lookup_hgt(x, y);
2018 					h0_ne = welt->lookup_hgt(x+1, y);
2019 					h0_se = welt->lookup_hgt(x+1, y+1);
2020 					h0_sw = welt->lookup_hgt(x, y+1);
2021 					if(  !gr2->is_water()  ) {
2022 						// while this appears to be a single height slope actually it is a double height slope half underwater
2023 						const sint8 water_hgt = welt->get_water_hgt(x, y);
2024 						h0_nw >= water_hgt ? h0_nw = h0 + corner_nw( gr2->get_grund_hang() ) : 0;
2025 						h0_ne >= water_hgt ? h0_ne = h0 + corner_ne( gr2->get_grund_hang() ) : 0;
2026 						h0_se >= water_hgt ? h0_se = h0 + corner_se( gr2->get_grund_hang() ) : 0;
2027 						h0_sw >= water_hgt ? h0_sw = h0 + corner_sw( gr2->get_grund_hang() ) : 0;
2028 					}
2029 				}
2030 				else {
2031 					// fully land
2032 					h0_nw = h0 + corner_nw( gr2->get_grund_hang() );
2033 					h0_ne = h0 + corner_ne( gr2->get_grund_hang() );
2034 					h0_se = h0 + corner_se( gr2->get_grund_hang() );
2035 					h0_sw = h0 + corner_sw( gr2->get_grund_hang() );
2036 				}
2037 
2038 
2039 				const sint8 hneu_nw = max( new_water_height, h0_nw );
2040 				const sint8 hneu_ne = max( new_water_height, h0_ne );
2041 				const sint8 hneu_se = max( new_water_height, h0_se );
2042 				const sint8 hneu_sw = max( new_water_height, h0_sw );
2043 				const sint8 hneu = min( min( hneu_nw, hneu_ne ), min( hneu_se, hneu_sw ) );
2044 
2045 				gr2->set_hoehe( hneu );
2046 
2047 				const uint8 sneu = (hneu_sw - hneu > 2 ? 2 : hneu_sw - hneu) + ((hneu_se - hneu > 2 ? 2 : hneu_se-hneu) * 3) + ((hneu_ne - hneu > 2 ? 2 : hneu_ne - hneu) * 9) + ((hneu_nw - hneu > 2 ? 2 : hneu_nw - hneu) * 27);
2048 				gr2->set_grund_hang( sneu );
2049 
2050 				welt->set_water_hgt(x, y, new_water_height );
2051 				welt->access(x, y)->correct_water();
2052 				welt->calc_climate( koord( x, y ), true );
2053 			}
2054 		}
2055 	}
2056 
2057 	delete [] stage;
2058 
2059 	return NULL;
2060 }
2061 
2062 
move(player_t * const player,uint16 const b,koord3d const pos)2063 char const* tool_plant_tree_t::move(player_t* const player, uint16 const b, koord3d const pos)
2064 {
2065 	if (b==0) {
2066 		return NULL;
2067 	}
2068 	if (env_t::networkmode) {
2069 		// queue tool for network
2070 		nwc_tool_t *nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false);
2071 		network_send_server(nwc);
2072 		return NULL;
2073 	}
2074 	else {
2075 		return work( player, pos );
2076 	}
2077 }
2078 
2079 
work(player_t * player,koord3d pos)2080 const char *tool_plant_tree_t::work( player_t *player, koord3d pos )
2081 {
2082 	koord k(pos.get_2d());
2083 
2084 	grund_t *gr = welt->lookup_kartenboden(k);
2085 	if(gr) {
2086 		// check if trees are allowed
2087 		if(  welt->get_settings().get_no_trees()  &&  !player->is_public_service()  ) {
2088 			return NOTICE_NO_TREES;
2089 		}
2090 
2091 		// check funds
2092 		sint64 const cost = welt->get_settings().cst_remove_tree;
2093 		if(  !player->can_afford(cost)  ) {
2094 			return NOTICE_INSUFFICIENT_FUNDS;
2095 		}
2096 
2097 		const tree_desc_t *desc = NULL;
2098 		bool check_climates = true;
2099 		bool random_age = false;
2100 		if(default_param==NULL  ||  strlen(default_param)==0) {
2101 			desc = baum_t::random_tree_for_climate( welt->get_climate( k ) );
2102 		}
2103 		else {
2104 			// parse default_param: bbdesc_nr b=1 ignore climate b=1 random age
2105 			check_climates = default_param[0]=='0';
2106 			random_age = default_param[1]=='1';
2107 			desc = baum_t::find_tree(default_param+3);
2108 		}
2109 		if(desc  &&  baum_t::plant_tree_on_coordinate( k, desc, check_climates, random_age )  ) {
2110 			player_t::book_construction_costs(player, cost, k, ignore_wt);
2111 			return NULL;
2112 		}
2113 		return "";
2114 	}
2115 	return NULL;
2116 }
2117 
2118 
2119 
2120 /* the following routines add waypoints/halts to a schedule
2121  * because we do not like to stop at AIs stop, but we still want to force the truck to use AI roads
2122  * So if there is a halt, then it must be either public or ours!
2123  * @author prissi
2124  */
tool_schedule_insert_aux(karte_t * welt,player_t * player,koord3d pos,schedule_t * schedule,bool append)2125 static const char *tool_schedule_insert_aux(karte_t *welt, player_t *player, koord3d pos, schedule_t *schedule, bool append)
2126 {
2127 	if(schedule == NULL) {
2128 		dbg->warning("tool_schedule_insert_aux()","Schedule is (null), doing nothing");
2129 		return 0;
2130 	}
2131 	grund_t *bd = welt->lookup(pos);
2132 	if (bd) {
2133 		// now just for error messages, we're assuming a valid ground
2134 		// check for right way type
2135 		if(!schedule->is_stop_allowed(bd)) {
2136 			return schedule->get_error_msg();
2137 		}
2138 		// and check for ownership
2139 		if(  !bd->is_halt()  ) {
2140 			weg_t *w = bd->get_weg( schedule->get_waytype() );
2141 			if(  w==NULL  &&  schedule->get_waytype()==tram_wt  ) {
2142 				w = bd->get_weg( track_wt );
2143 			}
2144 			if(  w!=NULL  &&  w->get_owner()!=welt->get_public_player()  &&  !player_t::check_owner(w->get_owner(),player)  ) {
2145 				return "Das Feld gehoert\neinem anderen Spieler\n";
2146 			}
2147 			if(  bd->get_depot()  &&  !player_t::check_owner( bd->get_depot()->get_owner(), player )  ) {
2148 				return "Das Feld gehoert\neinem anderen Spieler\n";
2149 			}
2150 		}
2151 		if(  bd->is_halt()  &&  !player_t::check_owner( player, bd->get_halt()->get_owner()) ) {
2152 			return "Das Feld gehoert\neinem anderen Spieler\n";
2153 		}
2154 		// ok, now we have a valid ground
2155 		if(append) {
2156 			schedule->append(bd);
2157 		}
2158 		else {
2159 			schedule->insert(bd);
2160 		}
2161 	}
2162 	return NULL;
2163 }
2164 
work(player_t * player,koord3d pos)2165 const char *tool_schedule_add_t::work( player_t *player, koord3d pos )
2166 {
2167 	return tool_schedule_insert_aux( welt, player, pos, (schedule_t*)const_cast<char *>(default_param), true );
2168 }
2169 
work(player_t * player,koord3d pos)2170 const char *tool_schedule_ins_t::work( player_t *player, koord3d pos )
2171 {
2172 	return tool_schedule_insert_aux( welt, player, pos, (schedule_t*)const_cast<char *>(default_param), false );
2173 }
2174 
2175 
2176 /* way construction */
2177 const way_desc_t *tool_build_way_t::defaults[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2178 
get_desc(uint16 timeline_year_month,bool remember) const2179 const way_desc_t *tool_build_way_t::get_desc( uint16 timeline_year_month, bool remember ) const
2180 {
2181 	const way_desc_t *desc = default_param ? way_builder_t::get_desc(default_param,0) :NULL;
2182 	if(  desc==NULL  &&  default_param  ) {
2183 		waytype_t wt = (waytype_t)atoi(default_param);
2184 		desc = defaults[wt&63];
2185 		if(desc==NULL  ||  !desc->is_available(timeline_year_month)) {
2186 			// search fastest way.
2187 			if(  wt == tram_wt  ||  wt == powerline_wt  ) {
2188 				desc = way_builder_t::weg_search(wt, 0xffffffff, timeline_year_month, type_flat);
2189 			}
2190 			else {
2191 				// this triggers an assertion if wt == powerline_wt
2192 				weg_t *w = weg_t::alloc(wt);
2193 				desc = w->get_desc();
2194 				delete w;
2195 			}
2196 		}
2197 	}
2198 	if(  desc  &&  remember  ) {
2199 		if(  desc->get_styp() == type_tram  ) {
2200 			defaults[ tram_wt ] = desc;
2201 		}
2202 		else {
2203 			defaults[desc->get_wtyp()&63] = desc;
2204 		}
2205 	}
2206 	return desc;
2207 }
2208 
get_icon(player_t *) const2209 image_id tool_build_way_t::get_icon(player_t *) const
2210 {
2211 	const way_desc_t *desc = way_builder_t::get_desc(default_param,0);
2212 	image_id image = icon;
2213 	bool is_tram = false;
2214 	if(  desc  ) {
2215 		is_tram = (desc->get_wtyp()==tram_wt) || (desc->get_styp() == type_tram);
2216 		if(  image ==  IMG_EMPTY  ) {
2217 			image = desc->get_cursor()->get_image_id(1);
2218 		}
2219 		if(  !desc->is_available( world()->get_timeline_year_month() )  ) {
2220 			return IMG_EMPTY;
2221 		}
2222 	}
2223 	if(  grund_t::underground_mode==grund_t::ugm_all && !is_tram ) {
2224 		return IMG_EMPTY;
2225 	}
2226 	return image;
2227 }
2228 
get_tooltip(const player_t *) const2229 const char* tool_build_way_t::get_tooltip(const player_t *) const
2230 {
2231 	const way_desc_t *desc = get_desc(welt->get_timeline_year_month(),false);
2232 	if (desc == NULL) {
2233 		return "";
2234 	}
2235 	tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() );
2236 	size_t n= strlen(toolstr);
2237 	sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed() );
2238 	return toolstr;
2239 }
2240 
2241 // default ways are not initialized synchronously for different clients
2242 // always return the name of a way, never the string containing the waytype
get_default_param(player_t * player) const2243 const char* tool_build_way_t::get_default_param(player_t *player) const
2244 {
2245 	if (player==NULL) {
2246 		return default_param;
2247 	}
2248 	if (desc) {
2249 		return desc->get_name();
2250 	}
2251 	else {
2252 		if (default_param == NULL) {
2253 			// no chance to guess anything sensible
2254 			return NULL;
2255 		}
2256 		const way_desc_t* test_desc = get_desc(0, false);
2257 		if (test_desc) {
2258 			return test_desc->get_name();
2259 		}
2260 		else {
2261 			return default_param;
2262 		}
2263 	}
2264 }
2265 
is_selected() const2266 bool tool_build_way_t::is_selected() const
2267 {
2268 	tool_t const* const tool = welt->get_tool(welt->get_active_player_nr());
2269 	if (tool->get_id() != get_id()) {
2270 		return false;
2271 	}
2272 	tool_build_way_t const* const selected = dynamic_cast<tool_build_way_t const*>(tool);
2273 	return (selected  &&  selected->get_desc(welt->get_timeline_year_month(),false) == get_desc(welt->get_timeline_year_month(),false));
2274 }
2275 
init(player_t * player)2276 bool tool_build_way_t::init( player_t *player )
2277 {
2278 	two_click_tool_t::init( player );
2279 	if( ok_sound == NO_SOUND ) {
2280 		ok_sound = SFX_CASH;
2281 	}
2282 
2283 	// now get current desc
2284 	desc = get_desc( welt->get_timeline_year_month(), can_use_gui() );
2285 	if(  desc  &&  desc->get_cursor()->get_image_id(0) != IMG_EMPTY  ) {
2286 		cursor = desc->get_cursor()->get_image_id(0);
2287 	}
2288 	if(  desc  &&  !desc->is_available(welt->get_timeline_year_month())  &&  player!=NULL  &&  player!=welt->get_public_player()  ) {
2289 		// non available way => fail
2290 		return false;
2291 	}
2292 	return desc!=NULL;
2293 }
2294 
get_waytype() const2295 waytype_t tool_build_way_t::get_waytype() const
2296 {
2297 	const way_desc_t *desc = get_desc( welt->get_timeline_year_month(), false );
2298 	if (desc) {
2299 		return desc->is_tram() ? tram_wt : desc->get_wtyp();
2300 	}
2301 	return invalid_wt;
2302 }
2303 
start_at(koord3d & new_start)2304 void tool_build_way_t::start_at( koord3d &new_start )
2305 {
2306 	if(  is_shift_pressed()  &&  (desc->get_styp() == type_elevated  &&  desc->get_wtyp() != air_wt)  ) {
2307 		grund_t *gr=welt->lookup(new_start);
2308 		if(  gr->get_weg( desc->get_waytype() )  ) {
2309 			new_start.z -= welt->get_settings().get_way_height_clearance();
2310 		}
2311 	}
2312 	// elevated ways with SHIFT will selected the current layer, when already on an elevated way
2313 	two_click_tool_t::start_at( new_start );
2314 }
2315 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d &)2316 uint8 tool_build_way_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d & )
2317 {
2318 	error = NULL;
2319 	grund_t *gr=welt->lookup(pos);
2320 	if(  gr  &&  slope_t::is_way(gr->get_weg_hang())  ) {
2321 		// ignore tunnel tiles (except road tunnel for tram track building ..)
2322 		if(  gr->get_typ() == grund_t::tunnelboden  &&  !gr->ist_karten_boden()  && !(desc->is_tram()  && gr->hat_weg(road_wt)) ) {
2323 			return 0;
2324 		}
2325 		bool const elevated = desc->get_styp() == type_elevated  &&  desc->get_wtyp() != air_wt;
2326 		// ignore water
2327 		if(  desc->get_wtyp() != water_wt  &&  gr->get_typ() == grund_t::wasser  ) {
2328 			if(  !elevated  ||  welt->lookup_hgt( pos.get_2d() ) < welt->get_water_hgt( pos.get_2d() )  ) {
2329 				return 0;
2330 			}
2331 			// here either channel or elevated way over not too deep water
2332 		}
2333 		// elevated ways have to check tile above
2334 		if(  elevated  ) {
2335 			gr = welt->lookup( pos + koord3d( 0, 0, welt->get_settings().get_way_height_clearance() ) );
2336 			if(  gr == NULL  ) {
2337 				return 2;
2338 			}
2339 			if(  gr->get_typ() != grund_t::monorailboden  ) {
2340 				return 0;
2341 			}
2342 		}
2343 		// test if way already exists on the way and if we are allowed to connect
2344 		weg_t *way = gr->get_weg(desc->get_wtyp());
2345 		if(  way  ) {
2346 			// allow to connect to any road
2347 			if(  desc->get_wtyp() == road_wt  ||  desc->get_wtyp() == water_wt  ) {
2348 				return 2;
2349 			}
2350 			error = way->is_deletable(player);
2351 			return error==NULL ? 2 : 0;
2352 		}
2353 		// check for ownership but ignore moving things
2354 		if(player!=NULL) {
2355 			for(uint8 i=0; i<gr->obj_count(); i++) {
2356 				obj_t* dt = gr->obj_bei(i);
2357 				if (!dt->is_moving()  &&  dt->is_deletable(player)!=NULL  &&  dt->get_typ()!=obj_t::label) {
2358 					error =  dt->is_deletable(player); // "Das Feld gehoert\neinem anderen Spieler\n";
2359 					return 0;
2360 				}
2361 			}
2362 		}
2363 	}
2364 	else {
2365 		return 0;
2366 	}
2367 	return 2;
2368 }
2369 
calc_route(way_builder_t & bauigel,const koord3d & start,const koord3d & end)2370 void tool_build_way_t::calc_route( way_builder_t &bauigel, const koord3d &start, const koord3d &end )
2371 {
2372 	// recalc type of construction
2373 	way_builder_t::bautyp_t bautyp = (way_builder_t::bautyp_t)desc->get_wtyp();
2374 	if(desc->is_tram()) {
2375 		bautyp = way_builder_t::schiene_tram;
2376 	}
2377 	// elevated track?
2378 	if(desc->get_styp()==type_elevated  &&  desc->get_wtyp()!=air_wt) {
2379 		bautyp |= way_builder_t::elevated_flag;
2380 	}
2381 
2382 	bauigel.init_builder(bautyp, desc);
2383 	if(  is_ctrl_pressed()  ) {
2384 		bauigel.set_keep_existing_ways( false );
2385 	}
2386 	else {
2387 		bauigel.set_keep_existing_faster_ways( true );
2388 	}
2389 
2390 	koord3d my_end = end;
2391 	// ending point is applied that elevated ways with SHIFT selects the current layer, when already on an elevated way
2392 	if(  is_shift_pressed()  &&  (desc->get_styp() == type_elevated  &&  desc->get_wtyp() != air_wt)  ) {
2393 		grund_t *gr=welt->lookup(my_end);
2394 		if(  gr->get_weg( desc->get_waytype() )  ) {
2395 			my_end.z -= welt->get_settings().get_way_height_clearance();
2396 		}
2397 	}
2398 	// and continue as normal ...
2399 	if(  is_ctrl_pressed()  ||  (env_t::straight_way_without_control  &&  !env_t::networkmode  &&  !is_scripted())  ) {
2400 		DBG_MESSAGE("tool_build_way_t()", "try straight route");
2401 		bauigel.calc_straight_route(start,my_end);
2402 	}
2403 	else {
2404 		bauigel.calc_route(start,my_end);
2405 	}
2406 	DBG_MESSAGE("tool_build_way_t()", "builder found route with %d squares length.", bauigel.get_count());
2407 }
2408 
do_work(player_t * player,const koord3d & start,const koord3d & end)2409 const char *tool_build_way_t::do_work( player_t *player, const koord3d &start, const koord3d &end )
2410 {
2411 	way_builder_t bauigel(player);
2412 	calc_route( bauigel, start, end );
2413 	if(  bauigel.get_route().get_count()>1  ) {
2414 		welt->mute_sound(true);
2415 		bauigel.build();
2416 		welt->mute_sound(false);
2417 
2418 		return NULL;
2419 	}
2420 	return "";
2421 }
2422 
mark_tiles(player_t * player,const koord3d & start,const koord3d & end)2423 void tool_build_way_t::mark_tiles(  player_t *player, const koord3d &start, const koord3d &end )
2424 {
2425 	way_builder_t bauigel(player);
2426 	calc_route( bauigel, start, end );
2427 
2428 	uint8 offset = (desc->get_styp() == type_elevated  &&  desc->get_wtyp() != air_wt) ? welt->get_settings().get_way_height_clearance() : 0;
2429 
2430 	if(  bauigel.get_count()>1  ) {
2431 		// Set tooltip first (no dummygrounds, if bauigel.calc_casts() is called).
2432 		win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", bauigel.calc_costs(), bauigel.get_count() ) );
2433 
2434 		// make dummy route from bauigel
2435 		for(  uint32 j=0;  j<bauigel.get_count();  j++   ) {
2436 			koord3d pos = bauigel.get_route()[j] + koord3d(0,0,offset);
2437 			grund_t *gr = welt->lookup( pos );
2438 			if( !gr ) {
2439 				gr = new monorailboden_t(pos, 0);
2440 				// should only be here when elevated/monorail, therefore will be at height offset above ground
2441 				gr->set_grund_hang( welt->lookup( pos - koord3d( 0, 0, offset ) )->get_grund_hang() );
2442 				welt->access(pos.get_2d())->boden_hinzufuegen(gr);
2443 			}
2444 			if (gr->is_water()) {
2445 				continue;
2446 			}
2447 			ribi_t::ribi zeige = gr->get_weg_ribi_unmasked(desc->get_wtyp()) | bauigel.get_route().get_ribi( j );
2448 
2449 			zeiger_t *way = new zeiger_t(pos, player);
2450 			if(gr->get_weg_hang()) {
2451 				way->set_image( desc->get_slope_image_id(gr->get_weg_hang(),0) );
2452 			}
2453 			else if(desc->get_wtyp()!=powerline_wt  &&  ribi_t::is_bend(zeige)  &&  desc->has_diagonal_image()) {
2454 				way->set_image( desc->get_diagonal_image_id(zeige,0) );
2455 			}
2456 			else {
2457 				way->set_image( desc->get_image_id(zeige,0) );
2458 			}
2459 			gr->obj_add( way );
2460 			way->set_yoff(-gr->get_weg_yoff() );
2461 			marked.insert( way );
2462 			way->mark_image_dirty( way->get_image(), 0 );
2463 		}
2464 	}
2465 }
2466 
2467 
2468 /* city road construction */
get_desc(uint16,bool) const2469 const way_desc_t *tool_build_cityroad::get_desc(uint16,bool) const
2470 {
2471 	return welt->get_city_road();
2472 }
2473 
do_work(player_t * player,const koord3d & start,const koord3d & end)2474 const char *tool_build_cityroad::do_work( player_t *player, const koord3d &start, const koord3d &end )
2475 {
2476 	way_builder_t bauigel(player);
2477 	bauigel.set_build_sidewalk(true);
2478 	calc_route( bauigel, start, end );
2479 	if(  bauigel.get_route().get_count()>1  ) {
2480 		welt->mute_sound(true);
2481 		bauigel.build();
2482 		welt->mute_sound(false);
2483 
2484 		return NULL;
2485 	}
2486 	return "";
2487 }
2488 
2489 
2490 /* bridge construction */
get_tooltip(const player_t *) const2491 const char* tool_build_bridge_t::get_tooltip(const player_t *) const
2492 {
2493 	const bridge_desc_t * desc = bridge_builder_t::get_desc(default_param);
2494 	if (desc == NULL) {
2495 		return "";
2496 	}
2497 	tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() );
2498 	size_t n= strlen(toolstr);
2499 	if(desc->get_waytype()!=powerline_wt) {
2500 		n += sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed());
2501 	}
2502 	if(desc->get_max_length()>0) {
2503 		n += sprintf(toolstr+n, ", %dkm", desc->get_max_length());
2504 	}
2505 	return toolstr;
2506 }
2507 
get_waytype() const2508 waytype_t tool_build_bridge_t::get_waytype() const
2509 {
2510 	const bridge_desc_t * desc = bridge_builder_t::get_desc(default_param);
2511 	return desc ? desc->get_waytype() : invalid_wt;
2512 }
2513 
2514 
init(player_t * player)2515 bool tool_build_bridge_t::init( player_t *player )
2516 {
2517 	two_click_tool_t::init( player );
2518 	// now get current desc
2519 	const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param);
2520 	if(  desc  &&  !desc->is_available(welt->get_timeline_year_month())  &&  player!=NULL  &&  player!=welt->get_public_player()  ) {
2521 		return false;
2522 	}
2523 	return desc!=NULL;
2524 }
2525 
2526 
do_work(player_t * player,const koord3d & start,const koord3d & end)2527 const char *tool_build_bridge_t::do_work( player_t *player, const koord3d &start, const koord3d &end )
2528 {
2529 	const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param);
2530 	if (end==koord3d::invalid) {
2531 		return bridge_builder_t::build( player, start, desc );
2532 	}
2533 	else {
2534 		const koord zv(ribi_type(end-start));
2535 		sint8 bridge_height;
2536 		const char *error;
2537 		koord3d end2 = bridge_builder_t::find_end_pos(player, start, zv, desc, error, bridge_height, false, koord_distance(start, end), is_ctrl_pressed());
2538 		if (end2 != end) {
2539 			return "End position is not valid"; // could only happen for scripts
2540 		}
2541 		bridge_builder_t::build_bridge( player, start, end, zv, bridge_height, desc, way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat));
2542 		return NULL; // all checks are performed before building.
2543 	}
2544 }
2545 
rdwr_custom_data(memory_rw_t * packet)2546 void tool_build_bridge_t::rdwr_custom_data(memory_rw_t *packet)
2547 {
2548 	two_click_tool_t::rdwr_custom_data(packet);
2549 	uint8 i = ribi;
2550 	packet->rdwr_byte(i);
2551 	ribi = (ribi_t::ribi)i;
2552 }
2553 
mark_tiles(player_t * player,const koord3d & start,const koord3d & end)2554 void tool_build_bridge_t::mark_tiles(  player_t *player, const koord3d &start, const koord3d &end )
2555 {
2556 	const ribi_t::ribi ribi_mark = ribi_type(end-start);
2557 	const koord zv(ribi_mark);
2558 	const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param);
2559 	const char *error;
2560 	sint8 bridge_height;
2561 	koord3d end2 = bridge_builder_t::find_end_pos(player, start, zv, desc, error, bridge_height, false, koord_distance(start, end), is_ctrl_pressed());
2562 	assert(end2 == end); (void)end2;
2563 
2564 	sint64 costs = 0;
2565 	// start
2566 	grund_t *gr = welt->lookup(start);
2567 
2568 	// get initial height of bridge from start tile
2569 	// flat -> height is 1 if conversion factor 1, 2 if conversion factor 2
2570 	// single height -> height is 1
2571 	// double height -> height is 2
2572 	const slope_t::type slope = gr->get_weg_hang();
2573 	uint8 max_height = slope ?  slope_t::max_diff(slope) : bridge_height;
2574 
2575 	zeiger_t *way = new zeiger_t(start, player );
2576 	const bridge_desc_t::img_t img0 = desc->get_end( slope, slope, slope_type(zv)*max_height );
2577 
2578 	gr->obj_add( way );
2579 	way->set_image( desc->get_background( img0, 0 ) );
2580 	way->set_foreground_image( desc->get_foreground( img0, 0 ) );
2581 
2582 	if(  gr->get_grund_hang() != 0  ) {
2583 		way->set_yoff( -TILE_HEIGHT_STEP * max_height );
2584 	}
2585 	// eventually we have to remove trees on start tile
2586 	if (desc->get_waytype() != powerline_wt) {
2587 		for(  uint8 i=0;  i<gr->get_top();  i++  ) {
2588 			obj_t *obj = gr->obj_bei(i);
2589 			switch(obj->get_typ()) {
2590 				case obj_t::baum:
2591 					costs -= welt->get_settings().cst_remove_tree;
2592 					break;
2593 				case obj_t::groundobj:
2594 					costs += ((groundobj_t *)obj)->get_desc()->get_price();
2595 					break;
2596 				default: break;
2597 			}
2598 		}
2599 	}
2600 	marked.insert( way );
2601 	way->mark_image_dirty( way->get_image(), 0 );
2602 	// loop
2603 	koord3d pos( start + zv + koord3d( 0, 0, max_height ) );
2604 	while (pos.get_2d()!=end.get_2d()) {
2605 		grund_t *gr = welt->lookup( pos );
2606 		if( !gr ) {
2607 			gr = new monorailboden_t(pos, 0);
2608 			gr->set_grund_hang( 0 );
2609 			welt->access(pos.get_2d())->boden_hinzufuegen(gr);
2610 		}
2611 		zeiger_t *way = new zeiger_t(pos, player );
2612 		gr->obj_add( way );
2613 		grund_t *kb = welt->lookup_kartenboden(pos.get_2d());
2614 		sint16 height = pos.z - kb->get_pos().z;
2615 		way->set_image(desc->get_background(desc->get_straight(ribi_mark,height-slope_t::max_diff(kb->get_grund_hang())),0));
2616 		way->set_foreground_image(desc->get_foreground(desc->get_straight(ribi_mark,height-slope_t::max_diff(kb->get_grund_hang())), 0));
2617 		marked.insert( way );
2618 		way->mark_image_dirty( way->get_image(), 0 );
2619 		pos = pos + zv;
2620 	}
2621 	costs += desc->get_price() * koord_distance(start, pos);
2622 	// end
2623 	gr = welt->lookup(end);
2624 
2625 	// get initial height of bridge from start tile
2626 	// flat -> height is 1 if conversion factor 1, 2 if conversion factor 2
2627 	// single height -> height is 1
2628 	// double height -> height is 2
2629 	const slope_t::type end_slope = gr->get_weg_hang();
2630 	const uint8 end_max_height = end_slope ? ((end_slope & 7) ? 1 : 2) : (pos.z-end.z);
2631 
2632 	if(  gr->ist_karten_boden()  &&  end.z + end_max_height == start.z + max_height  ) {
2633 		zeiger_t *way = new zeiger_t(end, player );
2634 		const bridge_desc_t::img_t img1 = desc->get_end( end_slope, end_slope, end_slope?0:(pos.z-end.z)*slope_type(-zv) );
2635 		gr->obj_add( way );
2636 		way->set_image(desc->get_background(img1, 0));
2637 		way->set_foreground_image(desc->get_foreground(img1, 0));
2638 		if(  gr->get_grund_hang() != 0  ) {
2639 			way->set_yoff( -TILE_HEIGHT_STEP * end_max_height );
2640 		}
2641 		marked.insert( way );
2642 		way->mark_image_dirty( way->get_image(), 0 );
2643 		costs += desc->get_price();
2644 	}
2645 	else {
2646 		if (desc->get_waytype() == powerline_wt  ? !gr->find<leitung_t>() : !gr->hat_weg(desc->get_waytype())) {
2647 			const way_desc_t *way_desc = way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat);
2648 			costs += way_desc->get_price();
2649 		}
2650 	}
2651 	// eventually we have to remove trees on end tile
2652 	if (desc->get_waytype() != powerline_wt) {
2653 		for(  uint8 i=0;  i<gr->get_top();  i++  ) {
2654 			obj_t *obj = gr->obj_bei(i);
2655 			switch(obj->get_typ()) {
2656 				case obj_t::baum:
2657 					costs -= welt->get_settings().cst_remove_tree;
2658 					break;
2659 				case obj_t::groundobj:
2660 					costs += ((groundobj_t *)obj)->get_desc()->get_price();
2661 					break;
2662 				default: break;
2663 			}
2664 		}
2665 	}
2666 	win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", costs, koord_distance(start, pos) ) );
2667 }
2668 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d & start)2669 uint8 tool_build_bridge_t::is_valid_pos(  player_t *player, const koord3d &pos, const char *&error, const koord3d &start )
2670 {
2671 	const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param);
2672 	const waytype_t wt = desc->get_waytype();
2673 
2674 	error = NULL;
2675 	grund_t *gr = welt->lookup(pos);
2676 	if(  gr==NULL  ||  !slope_t::is_way(gr->get_grund_hang())  ||  !bridge_builder_t::can_place_ramp( player, gr, wt, (is_first_click() ? 0 : ribi_type(pos-start)) )  ) {
2677 		return 0;
2678 	}
2679 
2680 	if(  welt->lookup( pos + koord3d(0, 0, 1))  ||  (welt->get_settings().get_way_height_clearance()==2  &&  welt->lookup( pos + koord3d(0, 0, 2) ))  ) {
2681 		return 0;
2682 	}
2683 
2684 	if(  is_first_click()  ) {
2685 		if(  gr->ist_karten_boden()  ) {
2686 			// first click
2687 			ribi_t::ribi rw = ribi_t::none;
2688 			if (wt==powerline_wt) {
2689 				if (gr->hat_wege()) {
2690 					return 0;
2691 				}
2692 				if (gr->find<leitung_t>()) {
2693 					rw |= gr->find<leitung_t>()->get_ribi();
2694 				}
2695 			}
2696 			else {
2697 				if (gr->find<leitung_t>()) {
2698 					return 0;
2699 				}
2700 				if(wt!=road_wt) {
2701 					// only road bridges can have other ways on it (ie trams)
2702 					if(gr->has_two_ways()  ||  (gr->hat_wege() && gr->get_weg_nr(0)->get_waytype()!=wt) ) {
2703 						return 0;
2704 					}
2705 					if(gr->hat_wege()){
2706 						rw |= gr->get_weg_nr(0)->get_ribi_unmasked();
2707 					}
2708 				}
2709 				else {
2710 					// If road and tram, we have to check both ribis.
2711 					for(int i=0;i<2;i++) {
2712 						const weg_t *w = gr->get_weg_nr(i);
2713 						if (w) {
2714 							if (w->get_waytype()!=road_wt  &&  !w->get_desc()->is_tram()) {
2715 								return 0;
2716 							}
2717 							rw |= w->get_ribi_unmasked();
2718 						}
2719 						else break;
2720 					}
2721 				}
2722 			}
2723 			// ribi from slope
2724 			rw |= ribi_type(gr->get_grund_hang());
2725 			if(  rw!=ribi_t::none && !ribi_t::is_single(rw)  ) {
2726 				return 0;
2727 			}
2728 			// determine possible directions
2729 			ribi = ribi_t::backward(rw);
2730 			return (ribi!=ribi_t::none ? 2 : 0) | (ribi_t::is_single(ribi) ? 1 : 0);
2731 		}
2732 		else {
2733 			if(  gr->get_weg_hang()  ) {
2734 				return 0;
2735 			}
2736 
2737 			if(  gr->get_typ() != grund_t::monorailboden  &&
2738 			     gr->get_typ() != grund_t::tunnelboden  ) {
2739 				return 0;
2740 			}
2741 
2742 			if(!gr->get_weg_nr(0)) {
2743 				return 0;
2744 			}
2745 
2746 			ribi = ~gr->get_weg_nr(0)->get_ribi_unmasked();
2747 
2748 			return 2;
2749 		}
2750 	}
2751 	else {
2752 		// second click
2753 
2754 		// dragging in the right direction?
2755 		ribi_t::ribi test = ribi_type(pos - start);
2756 		if (!ribi_t::is_single(test)  ||  ((test & (~ribi))!=0) ) {
2757 			return 0;
2758 		}
2759 
2760 		// check whether we can build a bridge here
2761 		const char *error = NULL;
2762 		sint8 bridge_height;
2763 		koord3d end = bridge_builder_t::find_end_pos(player, start, koord(test), desc, error, bridge_height, false, koord_distance(start, pos), is_ctrl_pressed());
2764 		if (end!=pos) {
2765 			return 0;
2766 		}
2767 		return 2;
2768 	}
2769 }
2770 
2771 
2772 /* more difficult, since this builds also underground ways */
get_tooltip(const player_t *) const2773 const char* tool_build_tunnel_t::get_tooltip(const player_t *) const
2774 {
2775 	const tunnel_desc_t * desc = tunnel_builder_t::get_desc(default_param);
2776 	tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() );
2777 	size_t n= strlen(toolstr);
2778 	if(desc->get_waytype()!=powerline_wt) {
2779 		n += sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed());
2780 	}
2781 	return toolstr;
2782 }
2783 
2784 
get_waytype() const2785 waytype_t tool_build_tunnel_t::get_waytype() const
2786 {
2787 	const tunnel_desc_t * desc = tunnel_builder_t::get_desc(default_param);
2788 	return desc ? desc->get_waytype() : invalid_wt;
2789 }
2790 
2791 
init(player_t * player)2792 bool tool_build_tunnel_t::init( player_t *player )
2793 {
2794 	two_click_tool_t::init( player );
2795 	// now get current desc
2796 	const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param);
2797 	if(  desc  &&  !desc->is_available(welt->get_timeline_year_month())  &&  player!=NULL  &&  player!=welt->get_public_player()  ) {
2798 		return false;
2799 	}
2800 	return desc!=NULL;
2801 }
2802 
2803 
check_pos(player_t * player,koord3d pos)2804 const char *tool_build_tunnel_t::check_pos( player_t *player, koord3d pos)
2805 {
2806 	if (grund_t::underground_mode == grund_t::ugm_all) {
2807 		return NULL;
2808 	}
2809 	else {
2810 		return two_click_tool_t::check_pos(player, pos);
2811 	}
2812 }
2813 
calc_route(way_builder_t & bauigel,const koord3d & start,const koord3d & end)2814 void tool_build_tunnel_t::calc_route( way_builder_t &bauigel, const koord3d &start, const koord3d &end)
2815 {
2816 	const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param);
2817 	way_builder_t::bautyp_t bt = (way_builder_t::bautyp_t)(desc->get_waytype());
2818 
2819 	const way_desc_t *wb = desc->get_way_desc();
2820 	if(wb==NULL) {
2821 		// ignore timeline to get consistent results
2822 		wb = way_builder_t::weg_search( desc->get_waytype(), desc->get_topspeed(), 0, type_flat );
2823 	}
2824 
2825 	bauigel.init_builder(bt | way_builder_t::tunnel_flag, wb, desc);
2826 	bauigel.set_keep_existing_faster_ways( !is_ctrl_pressed() );
2827 	// wegbauer (way builder) tries to find route to 3d coordinate if no ground at end exists or is not kartenboden (map ground)
2828 	bauigel.calc_straight_route(start,end);
2829 }
2830 
do_work(player_t * player,const koord3d & start,const koord3d & end)2831 const char *tool_build_tunnel_t::do_work( player_t *player, const koord3d &start, const koord3d &end )
2832 {
2833 	if( end == koord3d::invalid ) {
2834 		// Build tunnel mouths
2835 		if (welt->lookup_kartenboden(start.get_2d())->get_hoehe() == start.z) {
2836 			const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param);
2837 			return tunnel_builder_t::build( player, start.get_2d(), desc, !is_ctrl_pressed() );
2838 		}
2839 		else {
2840 			return "";
2841 		}
2842 	}
2843 	else {
2844 		// Build tunnels
2845 		way_builder_t bauigel(player);
2846 		calc_route( bauigel, start, end );
2847 		welt->mute_sound(true);
2848 		bauigel.build();
2849 		welt->mute_sound(false);
2850 		welt->lookup_kartenboden(end.get_2d())->clear_flag(grund_t::marked);
2851 		return NULL;
2852 	}
2853 }
2854 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d &)2855 uint8 tool_build_tunnel_t::is_valid_pos(  player_t *player, const koord3d &pos, const char *&error, const koord3d & )
2856 {
2857 	if(  !is_first_click()  ) {
2858 		error = NULL;
2859 		// All pos are valid for the second click!
2860 		return 2;
2861 	}
2862 	// search for ground
2863 	// start needs valid tile!
2864 	grund_t *gr = welt->lookup(pos);
2865 	if(  gr  ) {
2866 		if( gr->hat_wege() ) {
2867 			const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param);
2868 			// use the check_owner routine of way_builder_t (not player_t!), needs an instance
2869 			weg_t *w = gr->get_weg_nr(0);
2870 			if(  w==NULL  ||  w->get_desc()->get_wtyp()!=desc->get_waytype()  ) {
2871 				error = NOTICE_UNSUITABLE_GROUND;
2872 				return 0;
2873 			}
2874 			way_builder_t bauigel(player);
2875 			if(!bauigel.check_owner( w->get_owner(), player )) {
2876 				error = "Das Feld gehoert\neinem anderen Spieler\n";
2877 				return 0;
2878 			}
2879 		}
2880 	}
2881 	else {
2882 		error = NOTICE_UNSUITABLE_GROUND;
2883 		return 0;
2884 	}
2885 	// if starting tile is tunnel .. build underground tracks
2886 	error = NULL;
2887 	if(gr->ist_tunnel()) {
2888 		return 2;
2889 	}
2890 	// .. otherwise build tunnel mouths (and tunnel behind)
2891 	else {
2892 		return 1;
2893 	}
2894 }
2895 
mark_tiles(player_t * player,const koord3d & start,const koord3d & end)2896 void tool_build_tunnel_t::mark_tiles(  player_t *player, const koord3d &start, const koord3d &end )
2897 {
2898 	way_builder_t bauigel(player);
2899 	calc_route( bauigel, start, end );
2900 
2901 	const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param);
2902 	// now we search a matching way for the tunnels top speed
2903 	const way_desc_t *wb = desc->get_way_desc();
2904 	if(wb==NULL) {
2905 		// ignore timeline to get consistent results
2906 		wb = way_builder_t::weg_search( desc->get_waytype(), desc->get_topspeed(), 0, type_flat );
2907 	}
2908 
2909 	welt->lookup_kartenboden(end.get_2d())->clear_flag(grund_t::marked);
2910 
2911 	if(  bauigel.get_count()>1  ) {
2912 		// Set tooltip first (no dummygrounds, if bauigel.calc_casts() is called).
2913 		win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", -bauigel.calc_costs(), bauigel.get_count() ) );
2914 
2915 		// make dummy route from bauigel
2916 		for(  uint32 j=0;  j<bauigel.get_count();  j++  ) {
2917 			koord3d pos = bauigel.get_route()[j];
2918 			grund_t *gr = welt->lookup(pos);
2919 			if( !gr ) {
2920 				// We need to create a dummy ground.
2921 				gr = new tunnelboden_t(pos, 0);
2922 				welt->access(pos.get_2d())->boden_hinzufuegen(gr);
2923 			}
2924 			ribi_t::ribi zeige = gr->get_weg_ribi_unmasked(wb->get_wtyp()) | bauigel.get_route().get_ribi( j );
2925 
2926 			zeiger_t *way = new zeiger_t(pos, player );
2927 			if(gr->get_weg_hang()) {
2928 				way->set_image( wb->get_slope_image_id(gr->get_weg_hang(),0) );
2929 			}
2930 			else if(wb->get_wtyp()!=powerline_wt  &&  ribi_t::is_bend(zeige)  &&  wb->has_diagonal_image()) {
2931 				way->set_image( wb->get_diagonal_image_id(zeige,0) );
2932 			}
2933 			else {
2934 				way->set_image( wb->get_image_id(zeige,0) );
2935 			}
2936 			gr->obj_add( way );
2937 			marked.insert( way );
2938 			way->mark_image_dirty( way->get_image(), 0 );
2939 		}
2940 		welt->lookup(end)->set_flag(grund_t::marked);
2941 	}
2942 }
2943 
2944 
2945 /* removes a way like a driving car ... */
get_tooltip(player_t const *) const2946 char const* tool_wayremover_t::get_tooltip(player_t const*) const
2947 {
2948 	switch(atoi(default_param)) {
2949 		case road_wt: return translator::translate("remove roads");
2950 		case tram_wt:
2951 		case track_wt: return translator::translate("remove tracks");
2952 		case maglev_wt: return translator::translate("remove maglev tracks");
2953 		case narrowgauge_wt: return translator::translate("remove narrowgauge tracks");
2954 		case monorail_wt: return translator::translate("remove monorails");
2955 		case water_wt: return translator::translate("remove channels");
2956 		case air_wt: return translator::translate("remove airstrips");
2957 		case powerline_wt: return translator::translate("remove powerlines");
2958 	}
2959 	return NULL;
2960 }
2961 
get_icon(player_t *) const2962 image_id tool_wayremover_t::get_icon(player_t *) const
2963 {
2964 	if(  default_param  &&  way_builder_t::waytype_available( (waytype_t)atoi(default_param), welt->get_timeline_year_month() )  ) {
2965 		return icon;
2966 	}
2967 	return IMG_EMPTY;
2968 }
2969 
get_waytype() const2970 waytype_t tool_wayremover_t::get_waytype() const
2971 {
2972 	return default_param ? (waytype_t)atoi(default_param) : invalid_wt;
2973 }
2974 
2975 class electron_t : public test_driver_t {
check_next_tile(const grund_t * gr) const2976 	bool check_next_tile(const grund_t* gr) const OVERRIDE { return gr->get_leitung()!=NULL; }
get_ribi(const grund_t * gr) const2977 	ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return gr->get_leitung()->get_ribi(); }
get_waytype() const2978 	waytype_t get_waytype() const OVERRIDE { return invalid_wt; }
get_cost(const grund_t *,const weg_t *,const sint32,ribi_t::ribi) const2979 	int get_cost(const grund_t *, const weg_t *, const sint32, ribi_t::ribi) const OVERRIDE { return 1; }
is_target(const grund_t *,const grund_t *) const2980 	bool is_target(const grund_t *,const grund_t *) const OVERRIDE { return false; }
2981 };
2982 
2983 class scenario_checker_t : public test_driver_t {
2984 public:
2985 	test_driver_t *other;
2986 	scenario_t *scenario;
2987 	uint16 id;
2988 	player_t *player;
~scenario_checker_t()2989 	~scenario_checker_t() { delete other; }
2990 
2991 	/**
2992 	 * checks for active scenario,
2993 	 * @returns scenario_checker_t if scenario active, the supplied test_driver otherwise
2994 	 */
apply(test_driver_t * test_driver,player_t * player,tool_t * tool)2995 	static test_driver_t* apply(test_driver_t *test_driver, player_t *player, tool_t *tool) {
2996 		karte_t *welt = world();
2997 		if (is_scenario()) {
2998 			scenario_checker_t *td2 = new scenario_checker_t();
2999 			td2->other = test_driver;
3000 			td2->scenario = welt->get_scenario();
3001 			td2->id = tool->get_id();
3002 			td2->player = player;
3003 			return td2;
3004 		}
3005 		return test_driver;
3006 	}
3007 private:
check_next_tile(const grund_t * gr) const3008 	bool check_next_tile(const grund_t* gr) const OVERRIDE { return other->check_next_tile(gr)  &&  scenario->is_work_allowed_here(player, id, other->get_waytype(), gr->get_pos())==NULL;}
get_ribi(const grund_t * gr) const3009 	ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return other->get_ribi(gr); }
get_waytype() const3010 	waytype_t get_waytype() const OVERRIDE { return other->get_waytype(); }
get_cost(const grund_t * gr,const weg_t * w,const sint32 max_speed,ribi_t::ribi from) const3011 	int get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const OVERRIDE { return other->get_cost(gr, w, max_speed, from); }
is_target(const grund_t * gr,const grund_t * gr2) const3012 	bool is_target(const grund_t *gr,const grund_t *gr2) const OVERRIDE { return other->is_target(gr,gr2); }
3013 };
3014 
mark_tiles(player_t * player,const koord3d & start,const koord3d & end)3015 void tool_wayremover_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end )
3016 {
3017 	route_t verbindung;
3018 	bool can_built = calc_route( verbindung, player, start, end );
3019 	if( can_built ) {
3020 		FOR(vector_tpl<koord3d>, const& pos, verbindung.get_route()) {
3021 			zeiger_t *marker = new zeiger_t(pos, NULL );
3022 			marker->set_image( cursor );
3023 			marker->mark_image_dirty( marker->get_image(), 0 );
3024 			marked.insert( marker );
3025 			welt->lookup(pos)->obj_add( marker );
3026 		}
3027 	}
3028 }
3029 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d &)3030 uint8 tool_wayremover_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d & )
3031 {
3032 	// search for starting ground
3033 	waytype_t wt = get_waytype();
3034 	grund_t *gr=tool_intern_koord_to_weg_grund(player,welt,pos,wt);
3035 	if(gr==NULL) {
3036 		DBG_MESSAGE("tool_wayremover_t()", "no ground on %i,%i",pos.x, pos.y);
3037 		// wrong ground or not this way here => exit
3038 		return 0;
3039 	}
3040 	// do not remove ground from depot
3041 	if(gr->get_depot()) {
3042 		error = NOTICE_UNSUITABLE_GROUND;
3043 		return 0;
3044 	}
3045 	if(is_scenario()) {
3046 		error = welt->get_scenario()->is_work_allowed_here(player, get_id(), wt, pos);
3047 		if (error) {
3048 			dbg->warning("tool_wayremover_t::is_within_limits()", error);
3049 			return 0;
3050 		}
3051 	}
3052 	error = NULL;
3053 	return 2;
3054 }
3055 
calc_route(route_t & verbindung,player_t * player,const koord3d & start,const koord3d & end)3056 bool tool_wayremover_t::calc_route( route_t &verbindung, player_t *player, const koord3d &start, const koord3d &end )
3057 {
3058 	waytype_t wt = get_waytype();
3059 	if (wt == tram_wt) {
3060 		wt = track_wt;
3061 	}
3062 
3063 	if(  start == end  ) {
3064 		verbindung.clear();
3065 		grund_t *gr=welt->lookup(start);
3066 		if(  gr  &&  (wt!=powerline_wt ? gr->get_weg(wt)!=NULL : gr->get_leitung()!=NULL) ) {
3067 			verbindung.append( start );
3068 		}
3069 	}
3070 	else {
3071 		// get a default vehikel
3072 		test_driver_t* test_driver;
3073 		if(  wt!=powerline_wt  ) {
3074 			vehicle_desc_t remover_desc(wt, 500, vehicle_desc_t::diesel );
3075 			vehicle_t *driver = vehicle_builder_t::build(start, player, NULL, &remover_desc);
3076 			driver->set_flag( obj_t::not_on_map );
3077 			test_driver = driver;
3078 		}
3079 		else {
3080 			test_driver = new electron_t();
3081 		}
3082 		test_driver = scenario_checker_t::apply(test_driver, player, this);
3083 
3084 		verbindung.calc_route(welt, start, end, test_driver, 0, 0);
3085 		delete test_driver;
3086 	}
3087 	DBG_MESSAGE("tool_wayremover_t()","route with %d tile found",verbindung.get_count());
3088 
3089 	calc_route_error = NULL;
3090 	bool can_delete = start == end  ||  verbindung.get_count()>1;
3091 	if(  can_delete  ) {
3092 		// found a route => check if I can delete anything on it
3093 		FOR(koord3d_vector_t, const& i, verbindung.get_route()) {
3094 			if (!can_delete) break;
3095 			grund_t const* const gr = welt->lookup(i);
3096 			if(  wt!=powerline_wt  ) {
3097 				// no way found
3098 				if(  gr==NULL  ||  gr->get_weg(wt)==NULL  ) {
3099 					can_delete = false;
3100 					break;
3101 				}
3102 				// check all if we want to delete the first on a no-ground tile
3103 				bool check_all = !gr->ist_karten_boden()  &&  gr->has_two_ways()  &&  gr->get_weg_nr(0)->get_waytype()==wt;
3104 				// we have to do a fine check
3105 				for( uint i=0;  i<gr->get_top()  &&  can_delete;  i++  ) {
3106 					obj_t *obj = gr->obj_bei(i);
3107 					const uint8 type = obj->get_typ();
3108 					// ignore pillars, powerlines
3109 					if (type == obj_t::pillar  ||  type==obj_t::leitung) {
3110 						continue;
3111 					}
3112 					// ignore flying aircraft
3113 					if (type == obj_t::air_vehicle  &&  !(static_cast<air_vehicle_t*>(obj)->is_on_ground())) {
3114 						continue;
3115 					}
3116 					const waytype_t obj_wt = obj->get_waytype();
3117 					// way-related things
3118 					if (obj_wt != invalid_wt) {
3119 						// check this thing if it has the same waytype or if we want to remove the whole bridge/tunnel tile
3120 						// special case: stations - take care not to produce station without any way
3121 						const bool lonely_station = type==obj_t::gebaeude  &&  !gr->has_two_ways();
3122 						if (check_all ||  obj_wt == wt  ||  lonely_station) {
3123 							can_delete = (calc_route_error = obj->is_deletable(player)) == NULL;
3124 						}
3125 					}
3126 					// all other stuff
3127 					else {
3128 						can_delete = (calc_route_error = obj->is_deletable(player)) == NULL;
3129 					}
3130 				}
3131 			}
3132 			else {
3133 				// for powerline: only a ground and a powerline to remove
3134 				if(  gr==NULL  ||  gr->get_leitung()==NULL  ||  (calc_route_error = gr->get_leitung()->is_deletable(player))!=NULL  ) {
3135 					can_delete = false;
3136 					break;
3137 				}
3138 			}
3139 		}
3140 	}
3141 	DBG_MESSAGE("tool_wayremover_t()", "route search returned %d", can_delete);
3142 
3143 	return can_delete;
3144 }
3145 
do_work(player_t * player,const koord3d & start,const koord3d & end)3146 const char *tool_wayremover_t::do_work( player_t *player, const koord3d &start, const koord3d &end )
3147 {
3148 	waytype_t wt = get_waytype();
3149 	route_t verbindung;
3150 	if( !calc_route( verbindung, player, start, end )  ) {
3151 		DBG_MESSAGE("tool_wayremover_t()","no route found");
3152 		if (calc_route_error  &&  *calc_route_error) {
3153 			return calc_route_error;
3154 		}
3155 		else {
3156 			return "Ways not connected";
3157 		}
3158 	}
3159 	bool can_delete = true;	// assume success
3160 
3161 	// if successful => delete everything
3162 	for( uint32 i=0;  i<verbindung.get_count();  i++  ) {
3163 
3164 		grund_t *gr=welt->lookup(verbindung.at(i));
3165 
3166 		// ground can be missing after deleting a bridge ...
3167 		if(gr  &&  !gr->is_water()) {
3168 
3169 			if(gr->ist_bruecke()) {
3170 				if(gr->find<bruecke_t>()->get_desc()->get_waytype()==wt) {
3171 					if(  bridge_builder_t::is_start_of_bridge(gr)  ) {
3172 						const char *err = NULL;
3173 						err = bridge_builder_t::remove(player,verbindung.at(i),wt);
3174 						if(err) {
3175 							return err;
3176 						}
3177 						gr = welt->lookup(verbindung.at(i));
3178 						if(  !gr  ) {
3179 							// happens with bridges without ramps
3180 							continue;
3181 						}
3182 					}
3183 					else {
3184 						// do not remove asphalt from a bridge ...
3185 						continue;
3186 					}
3187 				}
3188 			}
3189 
3190 			// now the tricky part: delete just part of a way (or everything, if possible)
3191 			// calculate remaining directions
3192 			ribi_t::ribi rem = 15 ^ ( verbindung.get_route().get_ribi(i) );
3193 			// if start=end tile then delete every direction
3194 			if(  verbindung.get_count() <= 1  ) {
3195 				rem = 0;
3196 			}
3197 
3198 			if(  wt!=powerline_wt  ) {
3199 				if(!gr->get_flag(grund_t::is_kartenboden)  &&  (gr->get_typ()==grund_t::tunnelboden  ||  gr->get_typ()==grund_t::monorailboden)  &&  gr->get_weg_nr(0)->get_waytype()==wt) {
3200 					can_delete &= gr->remove_everything_from_way(player,wt,rem);
3201 					if(can_delete  &&  gr->get_weg(wt)==NULL) {
3202 						if(gr->get_weg_nr(0)!=0) {
3203 							gr->remove_everything_from_way(player,gr->get_weg_nr(0)->get_waytype(),ribi_t::none);
3204 						}
3205 						gr->obj_loesche_alle(player);
3206 						gr->mark_image_dirty();
3207 						if (gr->is_visible() && gr->get_typ()==grund_t::tunnelboden && i>0) { // visibility test does not influence execution
3208 							grund_t *bd = welt->access(verbindung.at(i-1).get_2d())->get_kartenboden();
3209 							bd->calc_image();
3210 							bd->set_flag(grund_t::dirty);
3211 						}
3212 						// delete tunnel ground too, if empty
3213 						welt->access(gr->get_pos().get_2d())->boden_entfernen(gr);
3214 						delete gr;
3215 					}
3216 				}
3217 				else {
3218 					can_delete &= gr->remove_everything_from_way(player,wt,rem);
3219 				}
3220 			}
3221 			else {
3222 				leitung_t *lt = gr->get_leitung();
3223 				if(  lt  &&  (rem&lt->get_ribi())==0  ) {
3224 					// remove only single connections
3225 					lt->cleanup(player);
3226 					delete lt;
3227 					// delete tunnel ground too, if empty
3228 					if (gr->get_typ()==grund_t::tunnelboden) {
3229 						gr->obj_loesche_alle(player);
3230 						gr->mark_image_dirty();
3231 						if (!gr->get_flag(grund_t::is_kartenboden)) {
3232 							welt->access(gr->get_pos().get_2d())->boden_entfernen(gr);
3233 							delete gr;
3234 						}
3235 						else {
3236 							grund_t *gr_new = new boden_t(gr->get_pos(), gr->get_grund_hang());
3237 							welt->access(gr->get_pos().get_2d())->boden_ersetzen(gr, gr_new);
3238 							gr_new->calc_image();
3239 						}
3240 					}
3241 				}
3242 				// otherwise it is a crossing ...
3243 			}
3244 		}
3245 		// ok, now everything removed ...
3246 	}
3247 
3248 	// return success
3249 	return can_delete ? NULL : "";
3250 }
3251 
3252 
3253 
3254 /* add catenary during construction */
3255 const way_obj_desc_t *tool_build_wayobj_t::default_electric = NULL;
3256 
get_tooltip(const player_t *) const3257 const char* tool_build_wayobj_t::get_tooltip(const player_t *) const
3258 {
3259 	if(  build  ) {
3260 		const way_obj_desc_t *desc = get_desc();
3261 		if(desc) {
3262 			tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() );
3263 			size_t n= strlen(toolstr);
3264 			if (desc->is_overhead_line()) {
3265 				// only overheadlines impose topspeed
3266 				sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed());
3267 			}
3268 			return toolstr;
3269 		}
3270 		return NULL;
3271 	}
3272 	else {
3273 		waytype_t wt = (waytype_t)atoi( default_param );
3274 		sprintf( toolstr, translator::translate("Remove wayobj %s"), translator::translate(weg_t::waytype_to_string(wt)) );
3275 		return toolstr;
3276 	}
3277 }
3278 
get_desc() const3279 const way_obj_desc_t *tool_build_wayobj_t::get_desc() const
3280 {
3281 	const way_obj_desc_t *desc = default_param ? wayobj_t::find_desc(default_param) : NULL;
3282 	if(desc==NULL) {
3283 		desc = default_electric;
3284 		if(desc==NULL) {
3285 			desc = wayobj_t::get_overhead_line( track_wt, welt->get_timeline_year_month() );
3286 		}
3287 	}
3288 	return desc;
3289 }
3290 
get_waytype() const3291 waytype_t tool_build_wayobj_t::get_waytype() const
3292 {
3293 	if(  build  ) {
3294 		const way_obj_desc_t *desc = get_desc();
3295 		return desc ? desc->get_wtyp() : invalid_wt;
3296 	}
3297 	else {
3298 		return default_param ? (waytype_t)atoi( default_param ) : invalid_wt;
3299 	}
3300 }
3301 
is_selected() const3302 bool tool_build_wayobj_t::is_selected() const
3303 {
3304 	const tool_build_wayobj_t *selected = dynamic_cast<const tool_build_wayobj_t *>(welt->get_tool(welt->get_active_player_nr()));
3305 	return (selected  &&  selected->build==build  &&  selected->get_desc() == get_desc());
3306 }
3307 
init(player_t * player)3308 bool tool_build_wayobj_t::init( player_t *player )
3309 {
3310 	two_click_tool_t::init( player );
3311 
3312 	if( build ) {
3313 		desc = get_desc();
3314 		if( desc ) {
3315 			cursor = desc->get_cursor()->get_image_id(0);
3316 			wt = desc->get_wtyp();
3317 			default_electric = desc;
3318 		}
3319 		return desc!=NULL;
3320 	}
3321 	else {
3322 		desc = NULL;
3323 		wt = (waytype_t)atoi( default_param );
3324 		return wt != 0;
3325 	}
3326 }
3327 
calc_route(route_t & verbindung,player_t * player,const koord3d & start,const koord3d & to)3328 bool tool_build_wayobj_t::calc_route( route_t &verbindung, player_t *player, const koord3d& start, const koord3d& to )
3329 {
3330 	waytype_t waytype = wt;
3331 	if(  waytype == any_wt  ) {
3332 		waytype = welt->lookup(start)->get_weg(wt)->get_waytype();
3333 	}
3334 	// special treatment for deports, since track electrication cannot "drive" into tram depot
3335 	if(  waytype == track_wt  ) {
3336 		if(  depot_t  *dp = welt->lookup(start)->get_depot()  ) {
3337 			waytype = dp->get_waytype();
3338 		}
3339 		else if(  depot_t  *dp = welt->lookup(to)->get_depot()  ) {
3340 			waytype = dp->get_waytype();
3341 		}
3342 	}
3343 	// get a default vehikel
3344 	vehicle_desc_t remover_desc( waytype, 500, vehicle_desc_t::diesel );
3345 	vehicle_t* test_vehicle = vehicle_builder_t::build(start, player, NULL, &remover_desc);
3346 	test_vehicle->set_flag( obj_t::not_on_map );
3347 	test_driver_t* test_driver = scenario_checker_t::apply(test_vehicle, player, this);
3348 
3349 	bool can_built;
3350 	if( start != to ) {
3351 		can_built = verbindung.calc_route(welt, start, to, test_driver, 0, 0);
3352 	}
3353 	else {
3354 		verbindung.clear();
3355 		verbindung.append( start );
3356 		can_built = true;
3357 	}
3358 	delete test_driver;
3359 	return can_built;
3360 }
3361 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d &)3362 uint8 tool_build_wayobj_t::is_valid_pos( player_t* player, const koord3d& pos, const char *&error, const koord3d & )
3363 {
3364 	// search for starting ground
3365 	grund_t *gr=tool_intern_koord_to_weg_grund(player, welt, pos, wt );
3366 	if(  gr == NULL  ) {
3367 		DBG_MESSAGE("tool_build_wayobj_t::is_within_limits()", "no ground on %s",pos.get_str());
3368 		// wrong ground or not this way here => exit
3369 		return 0;
3370 	}
3371 	error = NULL;
3372 	return 2;
3373 }
3374 
mark_tiles(player_t * player,const koord3d & start,const koord3d & end)3375 void tool_build_wayobj_t::mark_tiles( player_t* player, const koord3d &start, const koord3d &end )
3376 {
3377 	route_t verbindung;
3378 	bool can_built = calc_route( verbindung, player, start, end );
3379 	if( can_built ) {
3380 		sint32 cost_estimate = 0;
3381 
3382 		bool keep_existing_faster_ways = !is_ctrl_pressed();
3383 
3384 		for( uint32 j = 0; j < verbindung.get_count(); j++ ) {
3385 			koord3d pos = verbindung.at(j);
3386 			grund_t *gr = welt->lookup(pos);
3387 
3388 			ribi_t::ribi show = verbindung.get_route().get_ribi(j);
3389 			// Search a matching catenary on gr.
3390 			wayobj_t *wayobj = gr->get_wayobj( wt );
3391 			if( build ) {
3392 				cost_estimate += desc->get_price();
3393 				if( wayobj ) {
3394 					show = show | wayobj->get_dir();
3395 					// Already a catenary here -> costs only, if new catenary is faster
3396 					if(  (wayobj->get_desc()->get_topspeed() >= desc->get_topspeed()  &&  keep_existing_faster_ways)  || wayobj->get_desc() == desc ) {
3397 						cost_estimate -= desc->get_price();
3398 					}
3399 				}
3400 			}
3401 			else if( wayobj ) {
3402 				cost_estimate += wayobj->get_desc()->get_price();
3403 			}
3404 
3405 			zeiger_t *way_obj = NULL;
3406 			if( build ) {
3407 				way_obj = new zeiger_t(pos, player );
3408 				if(  gr->get_weg_hang()  ) {
3409 					way_obj->set_foreground_image( desc->get_front_slope_image_id(gr->get_weg_hang()) );
3410 					way_obj->set_image( desc->get_back_slope_image_id(gr->get_weg_hang()) );
3411 				}
3412 				else if(  ribi_t::is_bend(show)  &&  desc->has_diagonal_image()  ) {
3413 					way_obj->set_foreground_image( desc->get_front_diagonal_image_id(show) );
3414 					way_obj->set_image( desc->get_back_diagonal_image_id(show) );
3415 				}
3416 				else {
3417 					way_obj->set_foreground_image( desc->get_front_image_id(show) );
3418 					way_obj->set_image( desc->get_back_image_id(show) );
3419 				}
3420 			}
3421 			else {
3422 				if( gr->get_wayobj( wt ) ) {
3423 					way_obj = new zeiger_t(pos, player );
3424 					way_obj->set_image( cursor ); //skinverwaltung_t::bauigelsymbol->get_image_id(0));
3425 				}
3426 			}
3427 			if( way_obj ) {
3428 				way_obj->mark_image_dirty( way_obj->get_image(), 0 );
3429 				gr->obj_add( way_obj );
3430 				marked.insert( way_obj );
3431 			}
3432 		}
3433 		win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", -cost_estimate, verbindung.get_count() ) );
3434 	}
3435 }
3436 
do_work(player_t * player,const koord3d & start,const koord3d & end)3437 const char *tool_build_wayobj_t::do_work( player_t* player, const koord3d &start, const koord3d &end )
3438 {
3439 	route_t verbindung;
3440 	bool can_built = calc_route( verbindung, player, start, end );
3441 	DBG_MESSAGE("tool_build_wayobj_t::work()","route search returned %d",can_built);
3442 
3443 	const char *err = NULL;
3444 
3445 	if(!can_built) {
3446 		return "Ways not connected";
3447 	}
3448 
3449 	bool keep_existing_faster_ways = !is_ctrl_pressed();
3450 
3451 	// build wayobj ...
3452 	koord3d_vector_t const& r = verbindung.get_route();
3453 	for(uint32 i=0;  i<verbindung.get_count();  i++  ) {
3454 		if( build ) {
3455 			wayobj_t::extend_wayobj(r[i], player, r.get_ribi(i), desc, keep_existing_faster_ways);
3456 		}
3457 		else {
3458 			grund_t *gr = welt->lookup(r[i]);
3459 			for(int n=0;  n<gr->get_top();  n++  ) {
3460 				obj_t *obj = gr->obj_bei(n);
3461 				if(  obj  &&  obj->get_typ()==obj_t::wayobj  ) {
3462 					wayobj_t *wo = static_cast<wayobj_t *>(obj);
3463 					if(  wo->get_waytype() == wt  ) {
3464 						// only remove matching waytype
3465 						const char *err = wo->is_deletable( player );
3466 						if( !err ) {
3467 							wo->cleanup( player );
3468 							delete wo;
3469 						}
3470 						else {
3471 							break;
3472 						}
3473 					}
3474 				}
3475 			}
3476 		}
3477 	}
3478 
3479 	// Update depots (maybe remove electric tab?). Depots can only be on first and last tile.
3480 	if(  depot_t *dep = welt->lookup(r[0])->get_depot()  ) {
3481 		dep->update_win();
3482 	}
3483 	if(  depot_t *dep = welt->lookup(r.back())->get_depot()  ) {
3484 		dep->update_win();
3485 	}
3486 
3487 	return err;
3488 }
3489 
3490 
3491 /* build all kind of station extension buildings */
tool_station_building_aux(player_t * player,bool extend_public_halt,koord3d pos,const building_desc_t * desc,sint8 rotation)3492 const char *tool_build_station_t::tool_station_building_aux(player_t *player, bool extend_public_halt, koord3d pos, const building_desc_t *desc, sint8 rotation )
3493 {
3494 	koord k = pos.get_2d();
3495 
3496 	// need kartenboden (map ground)
3497 	if (welt->lookup_kartenboden(k)->get_hoehe() != pos.z) {
3498 		return "";
3499 	}
3500 DBG_MESSAGE("tool_station_building_aux()", "building mail office/station building on square %d,%d", k.x, k.y);
3501 
3502 	// Player player pays for the construction
3503 	// but we try to extend stations of Player new_owner that may be the public player
3504 	player_t *new_owner = extend_public_halt ? welt->get_public_player() : player;
3505 
3506 	koord offsets;
3507 	halthandle_t halt;
3508 	const char *msg = NOTICE_TILE_FULL;
3509 
3510 	if(  rotation==-1  ) {
3511 		//no predefined rotation
3512 
3513 		int best_halt = 0;
3514 		int any_halt = 0;
3515 
3516 		// find valid rotations (since halt extensions are symmetric, we need to check only two)
3517 		bool any_ok = false;
3518 		for( int r=0;  r<2;  r++  ) {
3519 			koord testsize = desc->get_size(r);
3520 			for(  sint8 j=3;  j>=0;  j-- ) {
3521 				bool ok = true;
3522 				koord offset(((j&1)^1)*(testsize.x-1),((j>>1)&1)*(testsize.y-1));
3523 				if(welt->square_is_free(k-offset, testsize.x, testsize.y, NULL, desc->get_allowed_climate_bits())) {
3524 					// first we must check over/under halt
3525 					halthandle_t last_halt;
3526 					for(  sint16 x=0;  x<testsize.x;  x++  ) {
3527 						for(  sint16 y=0;  y<testsize.y;  y++  ) {
3528 							const planquadrat_t *pl = welt->access( k-offset+koord(x,y) );
3529 							if (pl) {
3530 								for(  uint8 i=0;  i < pl->get_boden_count();  i++  ) {
3531 									halthandle_t test_halt = pl->get_boden_bei(i)->get_halt();
3532 									if(test_halt.is_bound()) {
3533 										if(!player_t::check_owner( new_owner, test_halt->get_owner())) {
3534 											// there is another player's halt
3535 											ok = false;
3536 											msg = "Das Feld gehoert\neinem anderen Spieler\n";
3537 										}
3538 										else if(!last_halt.is_bound()) {
3539 											last_halt = test_halt;
3540 										}
3541 										else if(last_halt != test_halt) {
3542 											// there are several halts
3543 											ok = false;
3544 											msg = "Several halts found.";
3545 										}
3546 									}
3547 								}
3548 							}
3549 						}
3550 					}
3551 					if(!ok) {
3552 						continue;
3553 					}
3554 					// well, at least this is theoretical possible here
3555 					any_ok = true;
3556 					if(rotation==-1) {
3557 						// we can build it. reserve this one
3558 						// This needs to build a building at under/over a halt.
3559 						rotation = r;
3560 						offsets = offset;
3561 					}
3562 					koord test_start = k-offset;
3563 
3564 					// find all surrounding tiles with a stop
3565 					// for following section of code arrays are arranged such that
3566 					// 0 - facing north
3567 					// 1 - facing west
3568 					// 2 - facing south
3569 					// 3 - facing east
3570 					int neighbour_halts[4] = { 0, 0, 0, 0 };
3571 					int best_halts[4] = { 0, 0, 0, 0 };
3572 
3573 					// test also diagonal corners (that is why from -1 to size!)
3574 					for(  sint16 y=-1;  y<=testsize.y;  y++  ) {
3575 						for(  sint16 x=-1;  x<=testsize.x;  (x==-1 && y>-1 && y<testsize.y)?x=testsize.x:x++  ) {
3576 							const planquadrat_t *pl = welt->access( test_start+koord(x,y) );
3577 							if(  pl  ) {
3578 								for(  uint b=0;  b < pl->get_boden_count();  b++  ) {
3579 									grund_t *gr = pl->get_boden_bei(b);
3580 									if(  gr->is_halt()  &&  gr->get_halt().is_bound() &&  new_owner == gr->get_halt()->get_owner()  ) {
3581 										halt = gr->get_halt();
3582 										gebaeude_t *gb = gr->find<gebaeude_t>();
3583 										bool best = gr->hat_wege()  &&  gb  &&  gb->get_tile()->get_desc()->get_extra()==desc->get_extra();
3584 
3585 										// north
3586 										if(  y==-1  ) {
3587 											neighbour_halts[0] ++;
3588 											if(  best  ) {
3589 												best_halts[0] ++;
3590 											}
3591 										}
3592 
3593 										// west
3594 										if(  x==-1  ) {
3595 											neighbour_halts[1] ++;
3596 											if(  best  ) {
3597 												best_halts[1] ++;
3598 											}
3599 										}
3600 
3601 										// south
3602 										if(  y==testsize.y  ) {
3603 											neighbour_halts[2] ++;
3604 											if(  best  ) {
3605 												best_halts[2] ++;
3606 											}
3607 										}
3608 
3609 										// east
3610 										if(  x==testsize.x  ) {
3611 											neighbour_halts[3] ++;
3612 											if(  best  ) {
3613 												best_halts[3] ++;
3614 											}
3615 										}
3616 									}
3617 								}
3618 							}
3619 						}
3620 					}
3621 
3622 					// now find out, if this offset/rotation is better ... (i.e. matches more fitting buildings)
3623 					// for r=0 we check north and south, for r=1 we check east and west
3624 					for(  int i=r;  i<4;  i+=2  ) {
3625 						if(  best_halts[i]>best_halt  ||  (best_halt==0  &&  neighbour_halts[i]>any_halt)  ) {
3626 							best_halt = best_halts[i];
3627 							any_halt = neighbour_halts[i];
3628 							rotation = i;
3629 							offsets = offset;
3630 						}
3631 					}
3632 				}
3633 			}
3634 		}
3635 
3636 		// no suitable ground here ...
3637 		if(  !any_ok  ) {
3638 			return msg;
3639 		}
3640 		// check over/under halt again
3641 		for(  sint16 x=0;  x<desc->get_x(rotation);  x++  ) {
3642 			for(  sint16 y=0;  y<desc->get_y(rotation);  y++  ) {
3643 				const planquadrat_t *pl = welt->access( k-offsets+koord(x,y) );
3644 				for(  uint8 i=0;  i < pl->get_boden_count();  i++  ) {
3645 					halthandle_t test_halt = pl->get_boden_bei(i)->get_halt();
3646 					if( test_halt.is_bound()  &&  player_t::check_owner( new_owner, test_halt->get_owner()) ) {
3647 						halt = test_halt;
3648 						break;
3649 					}
3650 				}
3651 			}
3652 		}
3653 		// is there no halt to connect?
3654 		if(  !halt.is_bound()  ) {
3655 			return "Post muss neben\nHaltestelle\nliegen!\n";
3656 		}
3657 	}
3658 	else {
3659 		// rotation was pre-selected; just search for stop now
3660 		assert(  rotation < desc->get_all_layouts()  );
3661 		koord testsize = desc->get_size(rotation);
3662 		offsets = koord(0,0);
3663 
3664 		if(  !welt->square_is_free(k, testsize.x, testsize.y, NULL, desc->get_allowed_climate_bits())  ) {
3665 			return NOTICE_TILE_FULL;
3666 		}
3667 		// check over/under halt
3668 		for(  sint16 x=0;  x<testsize.x;  x++  ) {
3669 			for(  sint16 y=0;  y<testsize.y;  y++  ) {
3670 				const planquadrat_t *pl = welt->access(k+koord(x,y));
3671 				for(  uint8 i=0;  i < pl->get_boden_count();  i++  ) {
3672 					halthandle_t test_halt = pl->get_boden_bei(i)->get_halt();
3673 					if(test_halt.is_bound()) {
3674 						if(!player_t::check_owner( new_owner, test_halt->get_owner())) {
3675 							return "Das Feld gehoert\neinem anderen Spieler\n";
3676 						}
3677 						else if(!halt.is_bound()) {
3678 							halt = test_halt;
3679 						}
3680 						else if(halt != test_halt) {
3681 							 return "Several halts found.";
3682 						}
3683 					}
3684 				}
3685 			}
3686 		}
3687 		if(!halt.is_bound()) {
3688 			halt = suche_nahe_haltestelle(new_owner, welt, welt->lookup_kartenboden(k)->get_pos(), desc->get_x(rotation), desc->get_y(rotation) );
3689 			// is there no halt to connect?
3690 			if(  !halt.is_bound()  ) {
3691 				return "Post muss neben\nHaltestelle\nliegen!\n";
3692 			}
3693 		}
3694 	}
3695 
3696 	if(  rotation>desc->get_all_layouts()  ) {
3697 		rotation %= desc->get_all_layouts();
3698 	}
3699 
3700 	hausbauer_t::build(halt->get_owner(), pos-offsets, rotation, desc, &halt);
3701 
3702 	sint32     const  factor = desc->get_x() * desc->get_y();
3703 	sint64     cost = -desc->get_price(welt) * factor;
3704 
3705 	if(  player!=halt->get_owner()  &&  halt->get_owner()==welt->get_public_player()  ) {
3706 		// public stops are expensive!
3707 		cost -= (desc->get_maintenance(welt) * factor * 60);
3708 	}
3709 	// difficult to distinguish correctly most suitable waytype
3710 	player_t::book_construction_costs(player,  cost, k, desc->get_finance_waytype());
3711 	halt->recalc_station_type();
3712 
3713 	return NULL;
3714 }
3715 
3716 /* build a dock either small or large */
tool_station_dock_aux(player_t * player,koord3d pos,const building_desc_t * desc)3717 const char *tool_build_station_t::tool_station_dock_aux(player_t *player, koord3d pos, const building_desc_t *desc)
3718 {
3719 	// the cursor cannot be outside the map from here on
3720 	koord k = pos.get_2d();
3721 	grund_t *gr = welt->lookup_kartenboden(k);
3722 	if (gr->get_hoehe()!= pos.z) {
3723 		return "";
3724 	}
3725 	slope_t::type hang = gr->get_grund_hang();
3726 	// first get the size
3727 	int len = desc->get_y()-1;
3728 	koord dx(hang);
3729 	koord last_k = k - dx*len;
3730 	halthandle_t halt;
3731 
3732 	// check, if we can build here ...
3733 	if(!slope_t::is_single(hang)) {
3734 		return "Dock must be built on single slope!";
3735 	}
3736 	else {
3737 		// iterate up to max(len,1) to ensure that there is at least one tile of water
3738 		// in front of the dock
3739 		for(int i=0;  i<=max(len,1);  i++  ) {
3740 			if(!welt->is_within_limits(k-dx*i)) {
3741 				// need at least a single tile to navigate ...
3742 				return "Zu nah am Kartenrand";
3743 			}
3744 			// search for nearby stops
3745 			const planquadrat_t* pl = welt->access(k-dx*i);
3746 			for(  uint8 j=0;  j < pl->get_boden_count();  j++  ) {
3747 				halthandle_t test_halt = pl->get_boden_bei(j)->get_halt();
3748 				if(test_halt.is_bound()) {
3749 					if(!player_t::check_owner( player, test_halt->get_owner())) {
3750 						return "Das Feld gehoert\neinem anderen Spieler\n";
3751 					}
3752 					else if(!halt.is_bound()) {
3753 						halt = test_halt;
3754 					}
3755 					else if(halt != test_halt) {
3756 						return "Several halts found.";
3757 					}
3758 				}
3759 			}
3760 
3761 			// check whether we can build something
3762 			const grund_t *gr=welt->lookup_kartenboden(k-dx*i);
3763 			if (gr->get_hoehe() != pos.z) {
3764 				return NOTICE_UNSUITABLE_GROUND;
3765 			}
3766 			if (i <= len) {
3767 				if (const char *msg = gr->kann_alle_obj_entfernen(player)) {
3768 					return msg;
3769 				}
3770 			}
3771 
3772 			if (i==0) {
3773 				// start tile on slope near water
3774 				if(gr->hat_wege()  ||  gr->get_typ()!=grund_t::boden  ||  gr->is_halt()) {
3775 					return NOTICE_TILE_FULL;
3776 				}
3777 			}
3778 			else {
3779 				// all other tiles in water (allowing one-tile docks on rivers)
3780 				if (!gr->is_water()  &&  !(len==0  &&  i==1  &&  gr->hat_weg(water_wt))) {
3781 					return NOTICE_UNSUITABLE_GROUND;
3782 				}
3783 				if (gr->find<gebaeude_t>()  ||  gr->get_depot()  ||  gr->is_halt()) {
3784 					return NOTICE_TILE_FULL;
3785 				}
3786 			}
3787 		}
3788 	}
3789 
3790 	// remove everything from tile
3791 	gr->obj_loesche_alle(player);
3792 
3793 	int layout = 0;
3794 	koord3d bau_pos = welt->lookup_kartenboden(k)->get_pos();
3795 	koord dx2;
3796 	switch(hang) {
3797 		case slope_t::south:
3798 		case slope_t::south*2:
3799 			layout = 0;
3800 			dx2 = koord::west;
3801 			break;
3802 		case slope_t::east:
3803 		case slope_t::east*2:
3804 			layout = 1;
3805 			dx2 = koord::north;
3806 			break;
3807 		case slope_t::north:
3808 		case slope_t::north*2:
3809 			layout = 2;
3810 			dx2 = koord::west;
3811 			bau_pos = welt->lookup_kartenboden(last_k)->get_pos();
3812 			break;
3813 		case slope_t::west:
3814 		case slope_t::west*2:
3815 			layout = 3;
3816 			dx2 = koord::north;
3817 			bau_pos = welt->lookup_kartenboden(last_k)->get_pos();
3818 			break;
3819 	}
3820 
3821 	// handle 16 layouts
3822 	bool change_layout = false;
3823 	if(desc->get_all_layouts()==16) {
3824 		if(  layout<2  ) {
3825 			layout = 15-layout;
3826 		}
3827 		else {
3828 			layout = 9-layout;
3829 		}
3830 		change_layout = true;
3831 	}
3832 
3833 	// oriented buildings here - get neighbouring layouts
3834 	const grund_t* gr_neigh = welt->lookup_kartenboden(k+dx2);
3835 
3836 	// find out if middle end or start tile
3837 	if(gr_neigh  &&  gr_neigh->is_halt()  &&  player_t::check_owner( player, gr_neigh->get_halt()->get_owner() )) {
3838 		gebaeude_t *gb = gr_neigh->find<gebaeude_t>();
3839 		if(gb  &&  (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock  ||  gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock)  ) {
3840 			if(change_layout) {
3841 				layout -= 4;
3842 			}
3843 			if(gb->get_tile()->get_desc()->get_all_layouts()==16) {
3844 				sint8 ly = gb->get_tile()->get_layout();
3845 				if(ly&0x02) {
3846 					gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFD,0,0), false );
3847 				}
3848 			}
3849 		}
3850 	}
3851 
3852 	gr_neigh = welt->lookup_kartenboden(k-dx2);
3853 	if(gr_neigh  &&  gr_neigh->is_halt()  &&  player_t::check_owner( player, gr_neigh->get_halt()->get_owner() )) {
3854 		gebaeude_t *gb = gr_neigh->find<gebaeude_t>();
3855 		if(gb  &&  (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock  ||  gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock)  ) {
3856 			if(change_layout) {
3857 				layout -= 2;
3858 			}
3859 			if(gb->get_tile()->get_desc()->get_all_layouts()==16) {
3860 				sint8 ly = gb->get_tile()->get_layout();
3861 				if(ly&0x04) {
3862 					gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFB,0,0), false );
3863 				}
3864 			}
3865 		}
3866 	}
3867 
3868 	if(!halt.is_bound()) {
3869 		halt = suche_nahe_haltestelle(player, welt, welt->lookup_kartenboden(k)->get_pos() );
3870 	}
3871 	bool neu = !halt.is_bound();
3872 
3873 	if(neu) {
3874 		if( gr && gr->get_halt().is_bound()  ) {
3875 			return "Das Feld gehoert\neinem anderen Spieler\n";
3876 		}
3877 		// ok, really new stop on this tile then
3878 		halt = haltestelle_t::create(k, player);
3879 	}
3880 	hausbauer_t::build(halt->get_owner(), bau_pos, layout, desc, &halt);
3881 	sint64 costs = -desc->get_price(welt);
3882 	if(  player!=halt->get_owner() && player != welt->get_public_player()  ) {
3883 		// public stops are expensive!
3884 		// (Except for the public player itself)
3885 		costs -= (desc->get_maintenance(welt) * 60);
3886 	}
3887 	for(  int i=0;  i<=len;  i++  ) {
3888 		koord p=k-dx*i;
3889 		player_t::book_construction_costs(player,  costs, p, water_wt);
3890 	}
3891 
3892 	halt->recalc_station_type();
3893 	if(  env_t::station_coverage_show  &&  welt->get_zeiger()->get_pos().get_2d()==k  ) {
3894 		// since we are larger now ...
3895 		halt->mark_unmark_coverage( true );
3896 	}
3897 
3898 	if(neu) {
3899 		char* const name = halt->create_name(k, "Dock");
3900 		halt->set_name( name );
3901 		free(name);
3902 	}
3903 	return NULL;
3904 }
3905 
3906 /* build a dock either small or large */
tool_station_flat_dock_aux(player_t * player,koord3d pos,const building_desc_t * desc,sint8 rotation)3907 const char *tool_build_station_t::tool_station_flat_dock_aux(player_t *player, koord3d pos, const building_desc_t *desc, sint8 rotation)
3908 {
3909 	// the cursor cannot be outside the map from here on
3910 	koord k = pos.get_2d();
3911 	grund_t *gr = welt->lookup_kartenboden(k);
3912 	if (gr->get_hoehe()!= pos.z) {
3913 		return "";
3914 	}
3915 	// first get the size
3916 	int len = desc->get_size().y-1;
3917 
3918 	// check, if we can build here ...
3919 	if(  !gr->ist_natur()  ||  gr->get_grund_hang() != slope_t::flat  ) {
3920 		return NOTICE_UNSUITABLE_GROUND;
3921 	}
3922 
3923 	// now find the direction
3924 	// first: find the next water
3925 	ribi_t::ribi water_dir = 0;
3926 	uint8        total_dir = 0;
3927 	for(  uint8 i=0;  i<4;  i++  ) {
3928 		if(  grund_t *gr = welt->lookup_kartenboden(k+koord::nsew[i])  ) {
3929 			if(  gr->is_water()  &&  gr->get_hoehe() == pos.z) {
3930 				water_dir |= ribi_t::nsew[i];
3931 				total_dir ++;
3932 			}
3933 		}
3934 	}
3935 
3936 	// not surrounded by water => fail
3937 	if(  total_dir == 0  ) {
3938 		return NOTICE_UNSUITABLE_GROUND;
3939 	}
3940 
3941 	// prefer layouts that reach an existing halt
3942 	ribi_t::ribi halt_dir = 0;
3943 	halthandle_t test_halt[4];
3944 
3945 	for(  uint8 ii=0;  ii<4;  ii++  ) {
3946 
3947 		if(  (water_dir & ribi_t::nsew[ii]) == 0  ) {
3948 			continue;
3949 		}
3950 		const koord dx = koord::nsew[ii];
3951 		const char *last_error = NULL;
3952 
3953 		for(int i=0;  i<=len;  i++  ) {
3954 
3955 			// check whether we can build something
3956 			const grund_t *gr = welt->lookup_kartenboden(k+dx*i);
3957 			if( !gr ) {
3958 				// need at least a single tile to navigate ...
3959 				last_error = "Zu nah am Kartenrand";
3960 				break;
3961 			}
3962 
3963 			if (gr->get_hoehe() != pos.z) {
3964 				return NOTICE_UNSUITABLE_GROUND;
3965 				break;
3966 			}
3967 
3968 			// search for nearby stops
3969 			const planquadrat_t* pl = welt->access(k+dx*i);
3970 			for(  uint8 j=0;  j < pl->get_boden_count()  &&  !test_halt[ii].is_bound();  j++  ) {
3971 				halthandle_t halt = pl->get_boden_bei(j)->get_halt();
3972 				if (halt.is_bound()  &&  player_t::check_owner( player, halt->get_owner()) ) {
3973 					test_halt[ii] = halt;
3974 					halt_dir |= ribi_t::nsew[ii];
3975 				}
3976 			}
3977 
3978 			if(  (last_error = gr->kann_alle_obj_entfernen(player))  ) {
3979 				break;
3980 			}
3981 
3982 			if (i>0) {
3983 				// all other tiles in water
3984 				if (!gr->is_water()  ||  gr->find<gebaeude_t>()  ||  gr->get_depot()  ||  gr->is_halt()) {
3985 					last_error = NOTICE_TILE_FULL;
3986 				}
3987 			}
3988 		}
3989 
3990 		// error: then remove this direction
3991 		if(  last_error  ) {
3992 			water_dir &= ~ribi_t::nsew[ii];
3993 			if(  --total_dir == 0  ) {
3994 				// no duitable directions found
3995 				return last_error;
3996 			}
3997 		}
3998 	}
3999 
4000 	// now we may have more than one dir left
4001 	if (rotation == -1  &&  total_dir > 1  &&  !ribi_t::is_single(water_dir & halt_dir) ) {
4002 		return "More than one possibility to build this dock found.";
4003 	}
4004 
4005 	// remove everything from tile
4006 	gr->obj_loesche_alle(player);
4007 
4008 	koord3d bau_pos = welt->lookup_kartenboden(k)->get_pos();
4009 	koord dx = koord::invalid;
4010 	koord last_k;
4011 	uint8 layout = 0; // building orientation
4012 	halthandle_t halt;
4013 
4014 	for(  uint8 i=0;  i<4;  i++  ) {
4015 		if(  water_dir & ribi_t::nsew[i]  ) {
4016 			dx = koord::nsew[i];
4017 			halt = test_halt[i];
4018 			koord last_k = k + dx*len;
4019 			// layout: north 2, west 3, south 0, east 1
4020 			static const uint8 nsew_to_layout[4] = { 2, 0, 1, 3 };
4021 			layout = nsew_to_layout[i];
4022 			if(  layout>=2  ) {
4023 				// reverse construction in these directions
4024 				bau_pos = welt->lookup_kartenboden(last_k)->get_pos();
4025 			}
4026 			if (rotation == layout) {
4027 				// desired rotation works
4028 				break;
4029 			}
4030 			if (rotation != -1) {
4031 				// desired rotation not possible, try others
4032 				if(  --total_dir == 0  ) {
4033 					return NOTICE_UNSUITABLE_GROUND;
4034 				}
4035 			}
4036 		}
4037 	}
4038 
4039 	// handle 16 layouts
4040 	bool change_layout = false;
4041 	if(desc->get_all_layouts()==16) {
4042 		if(  layout<2  ) {
4043 			layout = 15-layout;
4044 		}
4045 		else {
4046 			layout = 9-layout;
4047 		}
4048 		change_layout = true;
4049 	}
4050 
4051 	// oriented buildings here - get neighbouring layouts
4052 	koord dx2 = dx;
4053 	dx2.rotate90(0);
4054 	gr = welt->lookup_kartenboden(k+dx2);
4055 
4056 	// find out if middle end or start tile
4057 	if(gr  &&  gr->is_halt()  &&  player_t::check_owner( player, gr->get_halt()->get_owner() )) {
4058 		gebaeude_t *gb = gr->find<gebaeude_t>();
4059 		if(gb  &&  (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock  ||  gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock)  ) {
4060 			if(change_layout) {
4061 				layout -= 4;
4062 			}
4063 			if(gb->get_tile()->get_desc()->get_all_layouts()==16) {
4064 				sint8 ly = gb->get_tile()->get_layout();
4065 				if(ly&0x02) {
4066 					gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFD,0,0), false );
4067 				}
4068 			}
4069 		}
4070 	}
4071 
4072 	gr = welt->lookup_kartenboden(k-dx2);
4073 	if(gr  &&  gr->is_halt()  &&  player_t::check_owner( player, gr->get_halt()->get_owner() )) {
4074 		gebaeude_t *gb = gr->find<gebaeude_t>();
4075 		if(gb  &&  (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock  ||  gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock)  ) {
4076 			if(change_layout) {
4077 				layout -= 2;
4078 			}
4079 			if(gb->get_tile()->get_desc()->get_all_layouts()==16) {
4080 				sint8 ly = gb->get_tile()->get_layout();
4081 				if(ly&0x04) {
4082 					gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFB,0,0), false );
4083 				}
4084 			}
4085 		}
4086 	}
4087 
4088 	DBG_MESSAGE("tool_station_flat_dock_aux()","building dock from square (%d,%d) to (%d,%d) layout=%i", k.x, k.y, last_k.x, last_k.y, layout );
4089 
4090 	if(!halt.is_bound()) {
4091 		halt = suche_nahe_haltestelle(player, welt, welt->lookup_kartenboden(k)->get_pos() );
4092 	}
4093 	bool neu = !halt.is_bound();
4094 
4095 	if(neu) {
4096 		if(  gr  &&  gr->get_halt().is_bound()  ) {
4097 			return "Das Feld gehoert\neinem anderen Spieler\n";
4098 		}
4099 		// ok, really new stop on this tile then
4100 		halt = haltestelle_t::create(k, player);
4101 	}
4102 
4103 	hausbauer_t::build(halt->get_owner(), bau_pos, layout, desc, &halt);
4104 	sint64 costs = -desc->get_price(welt);
4105 	if(  player!=halt->get_owner() && player != welt->get_public_player()  ) {
4106 		// public stops are expensive!
4107 		// (Except for the public player itself)
4108 		costs -= (desc->get_maintenance(welt) * 60);
4109 	}
4110 	for(  int i=0;  i<=len;  i++  ) {
4111 		koord p=k-dx*i;
4112 		player_t::book_construction_costs(player,  costs, p, water_wt);
4113 	}
4114 
4115 	halt->recalc_station_type();
4116 
4117 	if(  env_t::station_coverage_show  &&  welt->get_zeiger()->get_pos().get_2d()==k  ) {
4118 		// since we are larger now ...
4119 		halt->mark_unmark_coverage( true );
4120 	}
4121 
4122 	if(neu) {
4123 		char* const name = halt->create_name(k, "Dock");
4124 		halt->set_name( name );
4125 		free(name);
4126 	}
4127 	else {
4128 		halt->recalc_basis_pos();
4129 	}
4130 	return NULL;
4131 }
4132 
4133 // build all types of stops but sea harbours
tool_station_aux(player_t * player,koord3d pos,const building_desc_t * desc,waytype_t wegtype,const char * type_name)4134 const char *tool_build_station_t::tool_station_aux(player_t *player, koord3d pos, const building_desc_t *desc, waytype_t wegtype, const char *type_name )
4135 {
4136 	koord k = pos.get_2d();
4137 DBG_MESSAGE("tool_station_aux()", "building %s on square %d,%d for waytype %x", desc->get_name(), k.x, k.y, wegtype);
4138 	const char *p_error=(desc->get_all_layouts()==4) ? "No terminal station here!" : "No through station here!";
4139 
4140 	// underground is checked in work(); if underground only simple stations are allowed
4141 	// get valid ground
4142 	grund_t *bd = tool_intern_koord_to_weg_grund(player, welt, pos, wegtype);
4143 
4144 	if(  !bd  ||  bd->get_weg_hang()!=slope_t::flat  ) {
4145 		// only flat tiles, only one stop per map square
4146 		return "No suitable way on the ground!";
4147 	}
4148 
4149 	if(  bd->ist_tunnel()  &&  bd->ist_karten_boden()  ) {
4150 		// do not build on tunnel entries
4151 		return "No suitable way on the ground!";
4152 	}
4153 
4154 	if(  bd->get_depot()  ) {
4155 		// not on depots
4156 		return NOTICE_UNSUITABLE_GROUND;
4157 	}
4158 
4159 	if(  bd->hat_weg(air_wt)  &&  bd->get_weg(air_wt)->get_desc()->get_styp()!=type_flat  ) {
4160 		return "Flugzeughalt muss auf\nRunway liegen!\n";
4161 	}
4162 
4163 	// find out orientation ...
4164 	uint32 layout = 0;
4165 	ribi_t::ribi ribi=ribi_t::none;
4166 	if(  desc->get_all_layouts()==2  ||  desc->get_all_layouts()==8  ||  desc->get_all_layouts()==16  ) {
4167 		// through station
4168 		if(  bd->has_two_ways()  ) {
4169 			// a crossing or maybe just a tram track on a road ...
4170 			ribi = bd->get_weg_nr(0)->get_ribi_unmasked()  |  bd->get_weg_nr(1)->get_ribi_unmasked();
4171 		}
4172 		else if(  bd->hat_wege()  ) {
4173 			ribi = bd->get_weg_nr(0)->get_ribi_unmasked();
4174 		}
4175 		// not straight: sorry cannot build here ...
4176 		if(  !ribi_t::is_straight(ribi)  ) {
4177 			return p_error;
4178 		}
4179 		layout = (ribi & ribi_t::northsouth)?0 :1;
4180 	}
4181 	else if(  desc->get_all_layouts()==4  ) {
4182 		// terminal station
4183 		if(  bd->hat_wege()  ) {
4184 			ribi = bd->get_weg_nr(0)->get_ribi_unmasked();
4185 		}
4186 		// sorry cannot build here ... (not a terminal tile)
4187 		if(  !ribi_t::is_single(ribi)  ) {
4188 			return p_error;
4189 		}
4190 
4191 		switch(ribi) {
4192 			//case ribi_t::south:layout = 0;  break;
4193 			case ribi_t::east:   layout = 1;    break;
4194 			case ribi_t::north:  layout = 2;    break;
4195 			case ribi_t::west:  layout = 3;    break;
4196 		}
4197 	}
4198 	else {
4199 		// something wrong with station number of layouts
4200 		dbg->fatal( "tool_station_t::tool_station_aux", "%s has wrong number of layouts (must be 2,4,8,16!)", desc->get_name() );
4201 		return p_error;
4202 	}
4203 
4204 	if(  desc->get_all_layouts() == 8  ||  desc->get_all_layouts() == 16  ) {
4205 		// through station - complex layout
4206 		// bits
4207 		// 1 = north south/east west (as simple layout)
4208 		// 2 = use far end image  \ can be combined
4209 		// 3 = use near end image / to use both end image
4210 		// 4 = platform face - 0 = far, 1 = near
4211 
4212 		// bit 1 has already been set
4213 
4214 		ribi_t::ribi next_own = ribi_t::none;
4215 
4216 		sint8 offset = bd->get_hoehe()+bd->get_weg_yoff()/TILE_HEIGHT_STEP;
4217 
4218 		grund_t *gr;
4219 		sint32 neighbour_layout[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
4220 		for(  unsigned i=0;  i<4;  i++  ) {
4221 			// oriented buildings here - get neighbouring layouts
4222 			gr = welt->lookup(koord3d(k+koord::nsew[i],offset));
4223 			if(!gr) {
4224 				// check whether bridge end tile
4225 				grund_t * gr_tmp = welt->lookup(koord3d(k+koord::nsew[i],offset-1));
4226 				if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) {
4227 					gr = gr_tmp;
4228 				}
4229 				else {
4230 					grund_t * gr_tmp = welt->lookup(koord3d(k+koord::nsew[i],offset-2));
4231 					if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 2) {
4232 						gr = gr_tmp;
4233 					}
4234 				}
4235 			}
4236 			if(  gr && gr->get_halt().is_bound()  ) {
4237 				// check, if there is an oriented stop
4238 				const gebaeude_t* gb = gr->find<gebaeude_t>();
4239 				if(gb  &&  gb->get_tile()->get_desc()->get_all_layouts()>4  &&  (gb->get_tile()->get_desc()->get_type()>building_desc_t::dock  ||  gb->get_tile()->get_desc()->get_type()>building_desc_t::flat_dock)  ) {
4240 					next_own |= ribi_t::nsew[i];
4241 					neighbour_layout[ribi_t::nsew[i]] = gb->get_tile()->get_layout();
4242 				}
4243 			}
4244 		}
4245 
4246 		// now for the details
4247 		ribi_t::ribi senkrecht = ~ribi_t::doubles(ribi);
4248 		ribi_t::ribi waagerecht = ribi_t::doubles(ribi);
4249 		if(next_own!=ribi_t::none) {
4250 			// oriented buildings here
4251 			if(ribi_t::is_single(ribi & next_own)) {
4252 				// only a single next neighbour on the same track
4253 				layout |= neighbour_layout[ribi & next_own] & 8;
4254 			}
4255 			else if(ribi_t::is_straight(ribi & next_own)) {
4256 				// two neighbours on the same track, use the north/west one
4257 				layout |= neighbour_layout[ribi & next_own & ribi_t::northwest] & 8;
4258 			}
4259 			else if(ribi_t::is_single((~ribi) & waagerecht & next_own)) {
4260 				// neighbour across break in track
4261 				layout |= neighbour_layout[(~ribi) & waagerecht & next_own] & 8;
4262 			}
4263 			else {
4264 				// no buildings left and right
4265 				// oriented buildings left and right
4266 				if(neighbour_layout[senkrecht & next_own & ribi_t::northwest] != -1) {
4267 					// just rotate layout
4268 					layout |= 8-(neighbour_layout[senkrecht & next_own & ribi_t::northwest]&8);
4269 				}
4270 				else {
4271 					if(neighbour_layout[senkrecht & next_own & ribi_t::southeast] != -1) {
4272 						layout |= 8-(neighbour_layout[senkrecht & next_own & ribi_t::southeast]&8);
4273 					}
4274 				}
4275 			}
4276 		}
4277 		// avoid orientation on 8 tiled buildings
4278 		layout &= (desc->get_all_layouts()-1);
4279 	}
4280 
4281 	halthandle_t old_halt = bd->get_halt();
4282 	sint64 old_cost = 0;
4283 	bool recalc_schedule = false;
4284 
4285 	halthandle_t halt;
4286 
4287 	if(  old_halt.is_bound()  ) {
4288 		gebaeude_t* gb = bd->find<gebaeude_t>();
4289 		const building_desc_t *old_desc = gb->get_tile()->get_desc();
4290 		if(  old_desc == desc  ) {
4291 			// already has the same station
4292 			return NULL;
4293 		}
4294 		if(  old_desc->get_capacity() >= desc->get_capacity()  &&  !is_ctrl_pressed()  ) {
4295 			return "Upgrade must have\na higher level";
4296 		}
4297 		old_cost = old_desc->get_price(welt)*old_desc->get_x()*old_desc->get_y();
4298 		gb->cleanup( NULL );
4299 		delete gb;
4300 		halt = old_halt;
4301 		if(  old_desc->get_enabled() != desc->get_enabled()  ) {
4302 			recalc_schedule = true;
4303 		}
4304 	}
4305 	else {
4306 		halt = suche_nahe_haltestelle(player,welt,bd->get_pos());
4307 	}
4308 
4309 	// seems everything ok, lets build
4310 	bool neu = !halt.is_bound();
4311 
4312 	if(neu) {
4313 		if(  bd && bd->get_halt().is_bound()  ) {
4314 			return "Das Feld gehoert\neinem anderen Spieler\n";
4315 		}
4316 		halt = haltestelle_t::create(k, player);
4317 	}
4318 	hausbauer_t::build_station_extension_depot(halt->get_owner(), bd->get_pos(), layout, desc, &halt);
4319 	halt->recalc_station_type();
4320 
4321 	if(neu) {
4322 		char* const name = halt->create_name(k, type_name);
4323 		halt->set_name(name);
4324 		free(name);
4325 	}
4326 	else {
4327 		halt->recalc_basis_pos();
4328 	}
4329 
4330 	// cost to build new station
4331 	sint64 cost = -desc->get_price(welt)*desc->get_x()*desc->get_y();
4332 	// discount for existing station
4333 	cost += old_cost/2;
4334 	if(  player!=halt->get_owner() && player != welt->get_public_player()  ) {
4335 		// public stops are expensive!
4336 		// (Except for the public player itself)
4337 		cost -= (desc->get_maintenance(welt) * desc->get_x() * desc->get_y() * 60);
4338 	}
4339 	player_t::book_construction_costs(player,  cost, k, wegtype);
4340 
4341 	if(  env_t::station_coverage_show  &&  welt->get_zeiger()->get_pos().get_2d()==k  ) {
4342 		// since we are larger now ...
4343 		halt->mark_unmark_coverage( true );
4344 	}
4345 
4346 	// the new station (after upgrading) might accept different goods => needs new schedule
4347 	if(  recalc_schedule  ) {
4348 		welt->set_schedule_counter();
4349 	}
4350 
4351 	return NULL;
4352 }
4353 
4354 // gives the description and sets the rotation value
get_desc(sint8 & rotation) const4355 const building_desc_t *tool_build_station_t::get_desc( sint8 &rotation ) const
4356 {
4357 	char *building = strdup( default_param );
4358 	const building_tile_desc_t *tdsc = NULL;
4359 	if(  building  ) {
4360 		char *p = strrchr( building, ',' );
4361 		if(  p  ) {
4362 			*p++ = 0;
4363 			rotation = atoi( p );
4364 		}
4365 		else {
4366 			rotation = -1;
4367 		}
4368 		tdsc = hausbauer_t::find_tile(building,0);
4369 		free( building );
4370 	}
4371 	if(  tdsc==NULL  ) {
4372 		return NULL;
4373 	}
4374 	return tdsc->get_desc();
4375 }
4376 
init(player_t *)4377 bool tool_build_station_t::init( player_t * )
4378 {
4379 	sint8 rotation = -1;
4380 	const building_desc_t *bdsc = get_desc( rotation );
4381 	if(  bdsc==NULL  ) {
4382 		return false;
4383 	}
4384 	cursor = bdsc->get_cursor()->get_image_id(0);
4385 	if(  !can_use_gui()  ) {
4386 		// do not change cursor
4387 		return true;
4388 	}
4389 	if(  (bdsc->get_type()==building_desc_t::generic_extension  ||  bdsc->get_type()==building_desc_t::flat_dock)  &&  bdsc->get_all_layouts()>1  ) {
4390 		if(  is_ctrl_pressed()  &&  rotation==-1  ) {
4391 			// call station dialog instead
4392 			destroy_win( magic_station_building_select );
4393 			create_win( new station_building_select_t(bdsc), w_info, magic_station_building_select);
4394 			// we do not activate building yet; else uncomment the return statement
4395 			return false;
4396 		}
4397 		else if(  rotation>=0  ) {
4398 			// rotation is already fixed
4399 			cursor_area = koord( bdsc->get_x(rotation), bdsc->get_y(rotation) );
4400 			cursor_centered = false;
4401 			cursor_offset = koord(0,0);
4402 			if (bdsc->get_type()==building_desc_t::flat_dock  &&  rotation >= 2 ) {
4403 				cursor_offset = cursor_area - koord(1,1);
4404 			}
4405 		}
4406 		else {
4407 			goto set_area_cov;
4408 		}
4409 	}
4410 	else {
4411 set_area_cov:
4412 		uint16 const cov = welt->get_settings().get_station_coverage() * 2 + 1;
4413 		cursor_area = koord(cov, cov);
4414 		cursor_centered = true;
4415 		cursor_offset = koord(0,0);
4416 	}
4417 	return true;
4418 }
4419 
4420 
get_icon(player_t *) const4421 image_id tool_build_station_t::get_icon( player_t * ) const
4422 {
4423 	sint8 dummy;
4424 	const building_desc_t *desc=get_desc(dummy);
4425 	if (desc == NULL) {
4426 		return IMG_EMPTY;
4427 	}
4428 	if(  grund_t::underground_mode==grund_t::ugm_all  ) {
4429 		// in underground mode, buildings will be done invisible above ground => disallow such confusion
4430 		if(  desc->get_type()!=building_desc_t::generic_stop  ||  desc->get_extra()==air_wt) {
4431 			return IMG_EMPTY;
4432 		}
4433 		if(  desc->get_type()==building_desc_t::generic_stop  &&  !desc->can_be_built_underground()) {
4434 			return IMG_EMPTY;
4435 		}
4436 	}
4437 	if(  grund_t::underground_mode==grund_t::ugm_none  ) {
4438 		if(  desc->get_type()==building_desc_t::generic_stop  &&  !desc->can_be_built_aboveground()) {
4439 			return IMG_EMPTY;
4440 		}
4441 	}
4442 	return icon;
4443 }
4444 
4445 
get_tooltip(const player_t *) const4446 const char* tool_build_station_t::get_tooltip(const player_t *) const
4447 {
4448 	sint8               dummy;
4449 	building_desc_t const* desc    = get_desc(dummy);
4450 	if (desc == NULL) {
4451 		return "";
4452 	}
4453 
4454 	sint64 price = 0;
4455 	sint64 maint = 0;
4456 	uint32 cap = desc->get_capacity(); // This is always correct in the desc object.
4457 
4458 	maint = desc->get_maintenance(welt);
4459 
4460 	if(  desc->get_type()==building_desc_t::generic_stop || desc->get_type()==building_desc_t::generic_extension || desc->get_type()==building_desc_t::dock || desc->get_type()==building_desc_t::flat_dock  ) {
4461 		price = -desc->get_price(welt);
4462 	}
4463 	else {
4464 		return "Illegal description";
4465 	}
4466 
4467 	if(desc->get_type()==building_desc_t::generic_extension || desc->get_type()==building_desc_t::dock || desc->get_type()==building_desc_t::flat_dock) {
4468 		const sint16 size_multiplier = desc->get_size().x * desc->get_size().y;
4469 		price *= size_multiplier;
4470 		cap *= size_multiplier;
4471 		maint *= size_multiplier;
4472 	}
4473 
4474 	return tooltip_with_price_maintenance_capacity(welt, desc->get_name(), price, maint, cap, desc->get_enabled());
4475 }
4476 
get_waytype() const4477 waytype_t tool_build_station_t::get_waytype() const
4478 {
4479 	sint8 dummy;
4480 	building_desc_t const* desc = get_desc(dummy);
4481 	switch (desc ? desc->get_type() : building_desc_t::generic_extension) {
4482 		case building_desc_t::generic_stop:
4483 			return (waytype_t)desc->get_extra();
4484 		case building_desc_t::dock:
4485 		case building_desc_t::flat_dock:
4486 			return water_wt;
4487 		case building_desc_t::generic_extension:
4488 		default:
4489 			return invalid_wt;
4490 	}
4491 }
4492 
4493 
check_pos(player_t *,koord3d pos)4494 const char *tool_build_station_t::check_pos( player_t*,  koord3d pos )
4495 {
4496 	if(  grund_t *gr = welt->lookup( pos )  ) {
4497 		sint8 rotation;
4498 		const building_desc_t *desc = get_desc(rotation);
4499 		if(desc == NULL) {
4500 			// tool is in bad state, eg due to invalid tool parameters
4501 			DBG_DEBUG("tool_build_station_t::check_pos()", "Cannot resolve building descriptor, default_param=\"%s\".", default_param);
4502 			return "ENGINE ERROR: Build station tool cannot resolve a building descriptor.";
4503 		}
4504 
4505 		if(  grund_t *bd = welt->lookup_kartenboden( pos.get_2d() )  ) {
4506 			const bool underground = bd->get_hoehe()>gr->get_hoehe();
4507 			if(  underground  ) {
4508 				// in underground mode, buildings will be done invisible above ground => disallow such confusion
4509 				if(  desc->get_type()!=building_desc_t::generic_stop  ||  desc->get_extra()==air_wt) {
4510 					return "Cannot built this station/building\nin underground mode here.";
4511 				}
4512 				if(  desc->get_type()==building_desc_t::generic_stop  &&  !desc->can_be_built_underground()) {
4513 					return "Cannot built this station/building\nin underground mode here.";
4514 				}
4515 			}
4516 			else if(  desc->get_type()==building_desc_t::generic_stop  &&  !desc->can_be_built_aboveground()) {
4517 				return "This station/building\ncan only be built underground.";
4518 			}
4519 			return NULL;
4520 		}
4521 	}
4522 	// no ground here???
4523 	return "Missing ground (fatal!)";
4524 }
4525 
4526 
move(player_t * player,uint16 buttonstate,koord3d pos)4527 const char *tool_build_station_t::move( player_t *player, uint16 buttonstate, koord3d pos )
4528 {
4529 	CHECK_FUNDS();
4530 
4531 	const char *result = NULL;
4532 	if(  buttonstate==1  ) {
4533 		const grund_t *gr = welt->lookup(pos);
4534 		if(!gr) {
4535 			return "";
4536 		}
4537 
4538 		// ownership allowed?
4539 		halthandle_t halt = gr->get_halt();
4540 		if(halt.is_bound()  &&  !player_t::check_owner( player, halt->get_owner())) {
4541 			return "";
4542 		}
4543 
4544 		if(  env_t::networkmode  ) {
4545 			// queue tool for network
4546 			nwc_tool_t *nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false);
4547 			network_send_server(nwc);
4548 		}
4549 		else {
4550 			result = work( player, pos );
4551 		}
4552 	}
4553 	return result;
4554 }
4555 
4556 
work(player_t * player,koord3d pos)4557 const char *tool_build_station_t::work( player_t *player, koord3d pos )
4558 {
4559 	const grund_t *gr = welt->lookup(pos);
4560 	if(!gr) {
4561 		return "";
4562 	}
4563 
4564 	// ownership allowed?
4565 	halthandle_t halt = gr->get_halt();
4566 	if(halt.is_bound()  &&  !player_t::check_owner( player, halt->get_owner())) {
4567 		return "Das Feld gehoert\neinem anderen Spieler\n";
4568 	}
4569 
4570 	// check underground / above ground
4571 	if (const char* msg = check_pos(player, pos)) {
4572 		return msg;
4573 	}
4574 
4575 	sint8 rotation = 0;
4576 	const building_desc_t *desc=get_desc(rotation);
4577 	const char *msg = NULL;
4578 	switch (desc->get_type()) {
4579 		case building_desc_t::dock:
4580 			msg = tool_build_station_t::tool_station_dock_aux(player, pos, desc );
4581 			break;
4582 		case building_desc_t::flat_dock:
4583 			msg = tool_build_station_t::tool_station_flat_dock_aux(player, pos, desc, rotation );
4584 			break;
4585 		case building_desc_t::generic_extension:
4586 			msg = tool_build_station_t::tool_station_building_aux(player, false, pos, desc, rotation );
4587 			if (msg) {
4588 				// try to build near a public halt
4589 				msg = tool_build_station_t::tool_station_building_aux(player, true, pos, desc, rotation );
4590 			}
4591 			break;
4592 		case building_desc_t::generic_stop: {
4593 			switch(desc->get_extra()) {
4594 				case road_wt:
4595 					msg = tool_build_station_t::tool_station_aux(player, pos, desc, road_wt, "H");
4596 					break;
4597 				case track_wt:
4598 				case monorail_wt:
4599 				case maglev_wt:
4600 				case narrowgauge_wt:
4601 				case tram_wt:
4602 					msg = tool_build_station_t::tool_station_aux(player, pos, desc, (waytype_t)desc->get_extra(), "BF");
4603 					break;
4604 				case water_wt:
4605 					msg = tool_build_station_t::tool_station_aux(player, pos, desc, water_wt, "Dock");
4606 					break;
4607 				case air_wt:
4608 					msg = tool_build_station_t::tool_station_aux(player, pos, desc, air_wt, "Airport");
4609 					break;
4610 			}
4611 			break;
4612 		}
4613 
4614 		default:
4615 			dbg->warning("tool_build_station_t::work()","tool called for illegal desc \"%\"", default_param );
4616 			msg = "Illegal station tool";
4617 	}
4618 	return msg;
4619 }
4620 
4621 
4622 
work(player_t * player,koord3d pos)4623 const char *tool_rotate_building_t::work( player_t *player, koord3d pos )
4624 {
4625 	const grund_t *gr = welt->lookup(pos);
4626 	if(!gr) {
4627 		return "";
4628 	}
4629 
4630 	if(  gebaeude_t* gb = gr->find<gebaeude_t>()  ) {
4631 
4632 		if(  !player_t::check_owner( gb->get_owner(), player )  ) {
4633 			return "Das Feld gehoert\neinem anderen Spieler\n";
4634 		}
4635 
4636 		// check for harbour (must not rotate)
4637 		const building_desc_t *desc = gb->get_tile()->get_desc();
4638 		if(  desc->get_all_layouts() == 1  ) {
4639 			// non rotatable => finish
4640 			return NULL;
4641 		}
4642 		if(  desc->get_type() == building_desc_t::dock  ) {
4643 			// cannot rotate a harbour
4644 			return "Cannot rotate this building!";
4645 		}
4646 		if(  desc->get_all_layouts()==2  &&  desc->get_x()!=desc->get_y()  ) {
4647 			// cannot rotate an asymmetric building with only two rotations
4648 			return "Cannot rotate this building!";
4649 		}
4650 
4651 		if(  gr->hat_wege()  ) {
4652 			// this is almost certainly a station ...
4653 			if(  desc->get_all_layouts()<16  ) {
4654 				// either symmetrical (==2, ==8) or freight loading station, so do not rotate!
4655 				return "Cannot rotate this building!";
4656 			}
4657 			int layout = gb->get_tile()->get_layout();
4658 			gb->set_tile( gb->get_tile()->get_desc()->get_tile( layout^8, 0, 0 ), false );
4659 		}
4660 		else {
4661 			// single and multitile buildings from here, include factories with holes etc.
4662 			bool rotate180 = desc->get_x() != desc->get_y();
4663 
4664 			if(  desc->get_x() != desc->get_y()  &&  desc->get_all_layouts()==2  ) {
4665 				// asymmetrical with only one rotation so do not rotate!
4666 				return "Cannot rotate this building!";
4667 			}
4668 
4669 			gb = gb->get_first_tile();
4670 			uint8 layout = gb->get_tile()->get_layout();
4671 			uint8 newlayout = (layout+1+rotate180) % desc->get_all_layouts();
4672 
4673 			// first test if all tiles are present (check for holes)
4674 			koord k;
4675 			for(k.x=0; k.x<desc->get_x(layout); k.x++) {
4676 				for(k.y=0; k.y<desc->get_y(layout); k.y++) {
4677 					grund_t *gr = welt->lookup( gb->get_pos()+k );
4678 					if(  !gr  ) {
4679 						return "Cannot rotate this building!";
4680 					}
4681 					const building_tile_desc_t *tile = desc->get_tile(newlayout, k.x, k.y);
4682 					gebaeude_t *gbt = gr->find<gebaeude_t>();
4683 					if(  tile==NULL  &&  gbt  ) {
4684 						return "Cannot rotate this building!";
4685 					}
4686 					if(  tile  &&  gbt==NULL  ) {
4687 						return "Cannot rotate this building!";
4688 					}
4689 				}
4690 			}
4691 			// ok, we can rotate it
4692 			for(k.x=0; k.x<desc->get_x(layout); k.x++) {
4693 				for(k.y=0; k.y<desc->get_y(layout); k.y++) {
4694 					grund_t *gr = welt->lookup( gb->get_pos()+k );
4695 					// there could be still holes, so the if is needed
4696 					if(  gebaeude_t *gb = gr->find<gebaeude_t>()  ) {
4697 						const building_tile_desc_t *tile = desc->get_tile(newlayout, k.x, k.y);
4698 						gb->set_tile( tile, false );
4699 					}
4700 				}
4701 			}
4702 		}
4703 	}
4704 	return NULL;
4705 }
4706 
4707 
4708 
get_tooltip(player_t const *) const4709 char const* tool_build_roadsign_t::get_tooltip(player_t const*) const
4710 {
4711 	const roadsign_desc_t * desc = roadsign_t::find_desc(default_param);
4712 	if(desc) {
4713 		return tooltip_with_price( desc->get_name(), -desc->get_price() );
4714 	}
4715 	return NULL;
4716 }
4717 
draw_after(scr_coord k,bool dirty) const4718 void tool_build_roadsign_t::draw_after(scr_coord k, bool dirty) const
4719 {
4720 	if(  icon!=IMG_EMPTY  &&  is_selected()  ) {
4721 		display_img_blend( icon, k.x, k.y, TRANSPARENT50_FLAG|OUTLINE_FLAG|color_idx_to_rgb(COL_BLACK), false, dirty );
4722 		char level_str[16];
4723 		sprintf(level_str, "%i", signal[welt->get_active_player_nr()].spacing);
4724 		display_proportional_rgb( k.x+4, k.y+4, level_str, ALIGN_LEFT, color_idx_to_rgb(COL_YELLOW), true );
4725 	}
4726 }
4727 
check_pos_intern(player_t * player,koord3d pos)4728 const char* tool_build_roadsign_t::check_pos_intern(player_t *player, koord3d pos)
4729 {
4730 	const char * error = "Hier kann kein\nSignal aufge-\nstellt werden!\n";
4731 	if (desc==NULL) {
4732 		// read data from string
4733 		desc = roadsign_t::find_desc(default_param);
4734 	}
4735 	if (desc==NULL) {
4736 		return error;
4737 	}
4738 	// search for starting ground
4739 	grund_t *gr = tool_intern_koord_to_weg_grund(player, welt, pos, desc->get_wtyp());
4740 	if(gr) {
4741 
4742 		signal_t *s = gr->find<signal_t>();
4743 		if(s  &&  s->get_desc()!=desc) {
4744 			// only one sign per tile
4745 			return error;
4746 		}
4747 
4748 		if(desc->is_signal_type()  &&  gr->find<roadsign_t>())  {
4749 			// only one sign per tile
4750 			return error;
4751 		}
4752 
4753 		// get the sign direction
4754 		weg_t *weg = gr->get_weg( desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt);
4755 		ribi_t::ribi dir = weg->get_ribi_unmasked();
4756 
4757 		// no signs on runways
4758 		if(  weg->get_waytype() == air_wt  &&  weg->get_desc()->get_styp() == type_runway  ) {
4759 			return error;
4760 		}
4761 
4762 		// no signals on switches
4763 		if(  ribi_t::is_threeway(dir)  &&  desc->is_signal_type()  ) {
4764 			return error;
4765 		}
4766 
4767 		if(  desc->is_private_way()  &&  !ribi_t::is_straight(dir)  ) {
4768 			// only on straight tiles ...
4769 			return error;
4770 		}
4771 
4772 		const bool two_way = desc->is_single_way()  ||  desc->is_signal_type();
4773 
4774 		if(!(desc->is_traffic_light() || two_way)  ||  (two_way  &&  ribi_t::is_twoway(dir))  ||  (desc->is_traffic_light()  &&  ribi_t::is_threeway(dir))) {
4775 			roadsign_t* rs;
4776 			if(  desc->is_signal_type()  ) {
4777 				// if there is already a signal, we might need to inverse the direction
4778 				rs = gr->find<signal_t>();
4779 				if (rs) {
4780 					if(  !player_t::check_owner( rs->get_owner(), player )  ) {
4781 						return "Das Feld gehoert\neinem anderen Spieler\n";
4782 					}
4783 				}
4784 			}
4785 			else {
4786 				// if there is already a sign, we might need to inverse the direction
4787 				rs = gr->find<roadsign_t>();
4788 				if (rs) {
4789 					if(  !player_t::check_owner( rs->get_owner(), player )  ) {
4790 						return "Das Feld gehoert\neinem anderen Spieler\n";
4791 					}
4792 				}
4793 			}
4794 			error = NULL;
4795 		}
4796 	}
4797 	return error;
4798 }
4799 
4800 
rdwr_custom_data(memory_rw_t * packet)4801 void tool_build_roadsign_t::rdwr_custom_data(memory_rw_t *packet)
4802 {
4803 	two_click_tool_t::rdwr_custom_data(packet);
4804 	packet->rdwr_byte(current.spacing);
4805 	packet->rdwr_bool(current.remove_intermediate);
4806 	packet->rdwr_bool(current.replace_other);
4807 }
4808 
4809 
get_waytype() const4810 waytype_t tool_build_roadsign_t::get_waytype() const
4811 {
4812 	return desc ? desc->get_wtyp() : invalid_wt;
4813 }
4814 
4815 
init(player_t * player)4816 bool tool_build_roadsign_t::init( player_t *player)
4817 {
4818 	desc = roadsign_t::find_desc(default_param);
4819 	// take default values from players settings
4820 	current = signal[player->get_player_nr()];
4821 
4822 	if (is_ctrl_pressed()  &&  can_use_gui()) {
4823 		create_win(new signal_spacing_frame_t(player, this), w_info, (ptrdiff_t)this);
4824 	}
4825 	return two_click_tool_t::init(player)  &&  (desc!=NULL);
4826 }
4827 
exit(player_t * player)4828 bool tool_build_roadsign_t::exit( player_t *player )
4829 {
4830 	destroy_win((ptrdiff_t)this);
4831 	return two_click_tool_t::exit(player);
4832 }
4833 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d & start)4834 uint8 tool_build_roadsign_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d &start)
4835 {
4836 	// first click
4837 	if (start==koord3d::invalid) {
4838 		error = check_pos_intern(player, pos);
4839 		return (error==NULL ? 3 : 0);
4840 	}
4841 	// second click
4842 	else {
4843 		error = NULL;
4844 		return 2;
4845 	}
4846 }
4847 
4848 
calc_route(route_t & verbindung,player_t * player,const koord3d & start,const koord3d & to)4849 bool tool_build_roadsign_t::calc_route( route_t &verbindung, player_t *player, const koord3d& start, const koord3d& to )
4850 {
4851 	// get a default vehikel
4852 	vehicle_desc_t rs_desc( desc->get_wtyp(), 500, vehicle_desc_t::diesel );
4853 	vehicle_t* test_vehicle = vehicle_builder_t::build(start, player, NULL, &rs_desc);
4854 	test_vehicle->set_flag(obj_t::not_on_map);
4855 	test_driver_t* test_driver = scenario_checker_t::apply(test_vehicle, player, this);
4856 
4857 	bool can_built;
4858 	if( start != to ) {
4859 		can_built = verbindung.calc_route(welt, start, to, test_driver, 0, 0);
4860 		// prevent building of many signals if start and to are adjacent
4861 		// but the step start->to is now allowed
4862 		if (can_built  &&  koord_distance(start, to)==1  &&  verbindung.get_count()>2) {
4863 			grund_t *gr, *grto = welt->lookup(to);
4864 			if(  welt->lookup(start)->get_neighbour(gr, desc->get_wtyp(), ribi_type(to-start) )  &&  gr==grto) {
4865 				can_built = false;
4866 			}
4867 		}
4868 	}
4869 	else {
4870 		verbindung.clear();
4871 		verbindung.append( start );
4872 		can_built = true;
4873 	}
4874 	delete test_driver;
4875 	return can_built;
4876 }
4877 
mark_tiles(player_t * player,const koord3d & start,const koord3d & ziel)4878 void tool_build_roadsign_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &ziel )
4879 {
4880 	route_t route;
4881 	if (!calc_route(route, player, start, ziel)) {
4882 		return;
4883 	}
4884 	signal_info const& s              = current;
4885 	uint8       const  signal_density = 2 * s.spacing;      // measured in half tiles (straight track count as 2, diagonal as 1, since sqrt(1/2) = 1/2 ;)
4886 	uint8              next_signal    = signal_density + 1; // to place a sign asap
4887 	sint32             cost           = 0;
4888 	directions.clear();
4889 	// dummy roadsign to get images for preview
4890 	roadsign_t *dummy_rs;
4891 	if (desc->is_signal_type()) {
4892 		dummy_rs = new signal_t(player, koord3d::invalid, ribi_t::none, desc, true);
4893 	}
4894 	else {
4895 		dummy_rs = new roadsign_t(player, koord3d::invalid, ribi_t::none, desc, true);
4896 	}
4897 	dummy_rs->set_flag(obj_t::not_on_map);
4898 
4899 	bool single_ribi = desc->is_signal_type() || desc->is_single_way() || desc->is_choose_sign();
4900 	for(  uint16 i = 0;  i < route.get_count();  i++  ) {
4901 		grund_t* gr = welt->lookup( route.at(i) );
4902 
4903 		weg_t *weg = gr->get_weg(desc->get_wtyp());
4904 		ribi_t::ribi ribi=weg->get_ribi_unmasked(); // set full ribi when signal is on a crossing.
4905 		if(  single_ribi  ) {
4906 			if(i>0) {
4907 				// take backward direction
4908 				ribi = ribi_type(route.at(i), route.at(i-1));
4909 			}
4910 			else {
4911 				// clear one direction bit to get single direction for signal
4912 				ribi &= ~ribi_type(route.at(i), route.at(i+1));
4913 			}
4914 		}
4915 
4916 		roadsign_t *rs = gr->find<signal_t>();
4917 		if (rs==NULL) {
4918 			rs = gr->find<roadsign_t>();
4919 		}
4920 
4921 		if (rs  &&  rs->get_waytype() != desc->get_waytype()) {
4922 			// do not delete signs from other ways
4923 			continue;
4924 		}
4925 
4926 		// check owner .. other signals...
4927 		bool straight = (i == 0)  ||  (i == route.get_count()-1)  ||  ribi_t::is_straight(ribi_type(route.at(i-1), route.at(i+1)));
4928 		next_signal += straight ? 2 : 1;
4929 		if(  next_signal >= signal_density  ) {
4930 			// can we place signal here?
4931 			if (check_pos_intern(player, route.at(i))==NULL  ||
4932 					(s.replace_other && rs && !rs->is_deletable(player))) {
4933 				zeiger_t* zeiger = new zeiger_t(gr->get_pos(), player );
4934 				marked.append(zeiger);
4935 				zeiger->set_image( skinverwaltung_t::bauigelsymbol->get_image_id(0) );
4936 				gr->obj_add( zeiger );
4937 				directions.append(ribi /* !=0 -> place sign*/);
4938 				next_signal = 0;
4939 				dummy_rs->set_pos(gr->get_pos());
4940 				dummy_rs->set_dir(ribi); // calls calc_image()
4941 				zeiger->set_foreground_image(dummy_rs->get_front_image());
4942 				zeiger->set_image(dummy_rs->get_image());
4943 				cost += rs ? (rs->get_desc()==desc ? 0  : desc->get_price()+rs->get_desc()->get_price()) : desc->get_price();
4944 			}
4945 		}
4946 		else if (s.remove_intermediate && rs && !rs->is_deletable(player)) {
4947 				zeiger_t* zeiger = new zeiger_t(gr->get_pos(), player );
4948 				marked.append(zeiger);
4949 				zeiger->set_image( tool_t::general_tool[TOOL_REMOVER]->cursor );
4950 				gr->obj_add( zeiger );
4951 				directions.append(ribi_t::none /*remove sign*/);
4952 				cost += rs->get_desc()->get_price();
4953 		}
4954 	}
4955 	delete dummy_rs;
4956 	win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", cost, route.get_count() ) );
4957 }
4958 
do_work(player_t * player,const koord3d & start,const koord3d & end)4959 const char *tool_build_roadsign_t::do_work( player_t *player, const koord3d &start, const koord3d &end)
4960 {
4961 	// read data from string
4962 	desc = roadsign_t::find_desc(default_param);
4963 	// single click ->place signal
4964 	if( end == koord3d::invalid  ||  start == end ) {
4965 		grund_t *gr = welt->lookup(start);
4966 		return place_sign_intern( player, gr );
4967 	}
4968 	// mark tiles to calculate positions of signals
4969 	mark_tiles(player, start, end);
4970 	// only search the marked tiles
4971 	uint32 j=0;
4972 	FOR(slist_tpl<zeiger_t*>, const i, marked) {
4973 		grund_t* const gr = welt->lookup(i->get_pos());
4974 		weg_t *weg = gr->get_weg(desc->get_wtyp());
4975 		ribi_t::ribi dir = directions[j++];
4976 		if (dir) {
4977 			// try to place signal
4978 			const char* error_text =  place_sign_intern( player, gr );
4979 			if(  error_text  ) {
4980 				if (signal[player->get_player_nr()].replace_other) {
4981 					roadsign_t* rs = gr->find<signal_t>();
4982 					if(rs == NULL) rs = gr->find<roadsign_t>();
4983 					if(  rs != NULL  &&  rs->is_deletable(player) == NULL  ) {
4984 						rs->cleanup(player);
4985 						delete rs;
4986 						error_text =  place_sign_intern( player, gr );
4987 					}
4988 				}
4989 			}
4990 			if(  error_text  ) {
4991 				return error_text;
4992 			}
4993 			roadsign_t* rs = gr->find<signal_t>();
4994 			if(rs == NULL) rs = gr->find<roadsign_t>();
4995 			assert(rs);
4996 			rs->set_dir(dir);
4997 		}
4998 		else {
4999 			// Place no signal -> remove existing signal
5000 			roadsign_t* rs = gr->find<signal_t>();
5001 			if(rs == NULL) rs = gr->find<roadsign_t>();
5002 			if(  rs != NULL  &&  rs->is_deletable(player) == NULL  ) {
5003 				rs->cleanup(player);
5004 				delete rs;
5005 			};
5006 		}
5007 		weg->count_sign();
5008 		gr->calc_image();
5009 	}
5010 	cleanup();
5011 	directions.clear();
5012 	return NULL;
5013 }
5014 
5015 /*
5016  * Called by the GUI (gui/signal_spacing.*)
5017  */
set_values(player_t * player,uint8 spacing,bool remove,bool replace)5018 void tool_build_roadsign_t::set_values( player_t *player, uint8 spacing, bool remove, bool replace )
5019 {
5020 	signal_info& s = signal[player->get_player_nr()];
5021 	s.spacing             = spacing;
5022 	s.remove_intermediate = remove;
5023 	s.replace_other       = replace;
5024 	current = s;
5025 }
5026 
5027 
get_values(player_t * player,uint8 & spacing,bool & remove,bool & replace)5028 void tool_build_roadsign_t::get_values( player_t *player, uint8 &spacing, bool &remove, bool &replace )
5029 {
5030 	signal_info const& s = signal[player->get_player_nr()];
5031 	spacing = s.spacing;
5032 	remove  = s.remove_intermediate;
5033 	replace = s.replace_other;
5034 }
5035 
5036 
place_sign_intern(player_t * player,grund_t * gr,const roadsign_desc_t *)5037 const char *tool_build_roadsign_t::place_sign_intern( player_t *player, grund_t* gr, const roadsign_desc_t*)
5038 {
5039 	const char *error = "Hier kann kein\nSignal aufge-\nstellt werden!\n";
5040 	// search for starting ground
5041 	if(gr) {
5042 		// get the sign direction
5043 		weg_t *weg = gr->get_weg( desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt);
5044 		roadsign_t *s = gr->find<signal_t>();
5045 		if(s==NULL) {
5046 			s = gr->find<roadsign_t>();
5047 		}
5048 		if(s  &&  s->get_desc()!=desc) {
5049 			// only one sign per tile
5050 			return error;
5051 		}
5052 		ribi_t::ribi dir = weg->get_ribi_unmasked();
5053 
5054 		const bool two_way = desc->is_single_way() || desc->is_signal_type();
5055 
5056 		if(!(desc->is_traffic_light() || two_way)  ||  (two_way  &&  ribi_t::is_twoway(dir))  ||  (desc->is_traffic_light()  &&  ribi_t::is_threeway(dir))) {
5057 			roadsign_t* rs;
5058 			if (desc->is_signal_type()) {
5059 				// if there is already a signal, we might need to inverse the direction
5060 				rs = gr->find<signal_t>();
5061 				if (rs) {
5062 					if(  !player_t::check_owner( rs->get_owner(), player )  ) {
5063 						return "Das Feld gehoert\neinem anderen Spieler\n";
5064 					}
5065 					// signals have three options
5066 					ribi_t::ribi sig_dir = rs->get_dir();
5067 					uint8 i = 0;
5068 					if (!ribi_t::is_twoway(sig_dir)) {
5069 						// inverse first dir
5070 						for (; i < 4; i++) {
5071 							if ((dir & ribi_t::nsew[i]) == sig_dir) {
5072 								i++;
5073 								break;
5074 							}
5075 						}
5076 					}
5077 					// find the second dir ...
5078 					for (; i < 4; i++) {
5079 						if ((dir & ribi_t::nsew[i]) != 0) {
5080 							dir = ribi_t::nsew[i];
5081 						}
5082 					}
5083 					// if nothing found, we have two ways again ...
5084 					rs->set_dir(dir);
5085 				}
5086 				else {
5087 					// add a new signal at position zero!
5088 					rs = new signal_t(player, gr->get_pos(), dir, desc);
5089 					DBG_MESSAGE("tool_roadsign()", "new signal, dir is %i", dir);
5090 					goto built_sign;
5091 				}
5092 			}
5093 			else {
5094 				// if there is already a sign, we might need to inverse the direction
5095 				rs = gr->find<roadsign_t>();
5096 				if (rs) {
5097 					if(  !player_t::check_owner( rs->get_owner(), player )  ) {
5098 						return "Das Feld gehoert\neinem anderen Spieler\n";
5099 					}
5100 					// reverse only if single way sign
5101 					if (desc->is_single_way() || desc->is_choose_sign()) {
5102 						dir = ~rs->get_dir() & weg->get_ribi_unmasked();
5103 						rs->set_dir(dir);
5104 						DBG_MESSAGE("tool_roadsign()", "reverse ribi %i", dir);
5105 					}
5106 				}
5107 				else {
5108 					// add a new roadsign at position zero!
5109 					// if single way, we need to reduce the allowed ribi to one
5110 					if (desc->is_single_way() || desc->is_choose_sign()) {
5111 						for(  int i=0;  i<4;  i++  ) {
5112 							if ((dir & ribi_t::nsew[i]) != 0) {
5113 								dir = ribi_t::nsew[i];
5114 								break;
5115 							}
5116 						}
5117 					}
5118 					DBG_MESSAGE("tool_roadsign()", "new roadsign, dir is %i", dir);
5119 					rs = new roadsign_t(player, gr->get_pos(), dir, desc);
5120 built_sign:
5121 					gr->obj_add(rs);
5122 					rs->finish_rd();	// to make them visible
5123 					weg->count_sign();
5124 					player_t::book_construction_costs(player, -desc->get_price(), gr->get_pos().get_2d(), weg->get_waytype());
5125 				}
5126 			}
5127 			error = NULL;
5128 		}
5129 	}
5130 	return error;
5131 }
5132 
5133 
5134 
5135 // built all types of depots
tool_depot_aux(player_t * player,koord3d pos,const building_desc_t * desc,waytype_t wegtype)5136 const char *tool_build_depot_t::tool_depot_aux(player_t *player, koord3d pos, const building_desc_t *desc, waytype_t wegtype)
5137 {
5138 	if(welt->is_within_limits(pos.get_2d())) {
5139 		grund_t *bd=NULL;
5140 		// special for the seven seas ...
5141 		if(wegtype==water_wt) {
5142 			bd = welt->lookup_kartenboden(pos.get_2d());
5143 			if(!bd->is_water()) {
5144 				bd = NULL;
5145 			}
5146 		}
5147 		if(bd==NULL) {
5148 			bd = tool_intern_koord_to_weg_grund(player,welt,pos,wegtype);
5149 		}
5150 		if(!bd  ||  bd->has_two_ways()) {
5151 			return NOTICE_DEPOT_BAD_POS;
5152 		}
5153 
5154 		// no depots on runways!
5155 		if(desc->get_extra()==air_wt  &&  bd->get_weg(air_wt)->get_desc()->get_styp()!=type_flat) {
5156 			return NOTICE_DEPOT_BAD_POS;
5157 		}
5158 
5159 		const char *p=bd->kann_alle_obj_entfernen(player);
5160 		if(p) {
5161 			return p;
5162 		}
5163 
5164 		// avoid building over a stop
5165 		if(bd->is_halt()  ||  bd->get_depot()!=NULL) {
5166 			return NOTICE_DEPOT_BAD_POS;
5167 		}
5168 
5169 		ribi_t::ribi ribi;
5170 		if(bd->is_water()) {
5171 			// assume one orientation with water
5172 			ribi = ribi_t::south;
5173 		}
5174 		else {
5175 			ribi = bd->get_weg_ribi_unmasked(wegtype);
5176 		}
5177 
5178 		if(ribi_t::is_single(ribi)  &&  bd->get_weg_hang()==0) {
5179 
5180 			int layout = 0;
5181 			switch(ribi) {
5182 				//case ribi_t::south:layout = 0;  break;
5183 				case ribi_t::east:   layout = 1;    break;
5184 				case ribi_t::north:  layout = 2;    break;
5185 				case ribi_t::west:  layout = 3;    break;
5186 			}
5187 			hausbauer_t::build_station_extension_depot(player, bd->get_pos(), layout, desc );
5188 			player_t::book_construction_costs(player, -desc->get_price(welt), pos.get_2d(), desc->get_finance_waytype());
5189 			if(can_use_gui()  &&  player == welt->get_active_player()) {
5190 				welt->set_tool( general_tool[TOOL_QUERY], player );
5191 			}
5192 
5193 			return NULL;
5194 		}
5195 		return NOTICE_DEPOT_BAD_POS;
5196 	}
5197 	return "";
5198 }
5199 
get_icon(player_t * player) const5200 image_id tool_build_depot_t::get_icon(player_t *player) const
5201 {
5202 	if(  player  &&  !player->is_public_service()  ) {
5203 		const building_desc_t *desc = hausbauer_t::find_tile(default_param,0)->get_desc();
5204 		const uint16 time = welt->get_timeline_year_month();
5205 		if(  desc  &&  desc->is_available(time)  ) {
5206 			return desc->get_cursor()->get_image_id(1);
5207 		}
5208 	}
5209 	return IMG_EMPTY;
5210 }
5211 
init(player_t * player)5212 bool tool_build_depot_t::init( player_t *player )
5213 {
5214 	building_desc_t const* desc = hausbauer_t::find_tile(default_param, 0)->get_desc();
5215 	if (desc == NULL) {
5216 		return false;
5217 	}
5218 	// no depots for player 1
5219 	if(player!=welt->get_public_player()) {
5220 		cursor = desc->get_cursor()->get_image_id(0);
5221 		return true;
5222 	}
5223 	return false;
5224 }
5225 
get_tooltip(const player_t *) const5226 const char* tool_build_depot_t::get_tooltip(const player_t *) const
5227 {
5228 	settings_t   const& settings = welt->get_settings();
5229 	building_desc_t const* desc    = hausbauer_t::find_tile(default_param, 0)->get_desc();
5230 	if (desc == NULL) {
5231 		return NULL;
5232 	}
5233 
5234 	char         const* tip;
5235 	switch (desc->get_extra()) {
5236 		case road_wt:        tip = "Build road depot";        break;
5237 		case track_wt:       tip = "Build train depot";       break;
5238 		case monorail_wt:    tip = "Build monorail depot";    break;
5239 		case maglev_wt:      tip = "Build maglev depot";      break;
5240 		case narrowgauge_wt: tip = "Build narrowgauge depot"; break;
5241 		case tram_wt:        tip = "Build tram depot";        break;
5242 		case water_wt:       tip = "Build ship depot";        break;
5243 		case air_wt:         tip = "Build air depot";         break;
5244 		default:             return 0;
5245 	}
5246 	return tooltip_with_price_maintenance(welt, tip, -desc->get_price(welt), settings.maint_building * desc->get_level());
5247 }
5248 
get_waytype() const5249 waytype_t tool_build_depot_t::get_waytype() const
5250 {
5251 	const building_desc_t *desc = hausbauer_t::find_tile(default_param,0)->get_desc();
5252 	return desc ? (waytype_t)desc->get_extra() : invalid_wt;
5253 }
5254 
work(player_t * player,koord3d pos)5255 const char *tool_build_depot_t::work( player_t *player, koord3d pos )
5256 {
5257 	if(player==welt->get_public_player()) {
5258 		// no depots for player 1
5259 		return 0;
5260 	}
5261 
5262 	building_desc_t const* const desc = hausbauer_t::find_tile(default_param,0)->get_desc();
5263 	switch(desc->get_extra()) {
5264 		case road_wt:
5265 		case track_wt:
5266 		case water_wt:
5267 		case air_wt:
5268 		case maglev_wt:
5269 		case narrowgauge_wt:
5270 			return tool_build_depot_t::tool_depot_aux(player, pos, desc, (waytype_t)desc->get_extra());
5271 
5272 		case monorail_wt:
5273 			{
5274 				// since it needs also a foundation, this is slightly more complex ...
5275 				char const* const err = tool_build_depot_t::tool_depot_aux(player, pos, desc, monorail_wt);
5276 				if(err==NULL) {
5277 					grund_t *bd = welt->lookup_kartenboden(pos.get_2d());
5278 					if(hausbauer_t::elevated_foundation_desc  &&  pos.z-bd->get_pos().z==1  &&  bd->ist_natur()) {
5279 						hausbauer_t::build(player, bd->get_pos(), 0, hausbauer_t::elevated_foundation_desc );
5280 					}
5281 				}
5282 				return err;
5283 			}
5284 		case tram_wt:
5285 			return tool_build_depot_t::tool_depot_aux(player, pos, desc, track_wt);
5286 		default:
5287 			dbg->warning("tool_build_depot()","called with unknown desc %s",desc->get_name() );
5288 			return "Unknown depot object";
5289 	}
5290 	return NULL;
5291 }
5292 
5293 
5294 
5295 /* builds (random) tourist attraction and maybe adds it to the next city
5296  * the parameter string is a follow:
5297  * 1#theater
5298  * first letter: ignore climates
5299  * second letter: rotation (0,1,2,3,#=random)
5300  * finally building name
5301  * @author prissi
5302  */
init(player_t *)5303 bool tool_build_house_t::init( player_t * )
5304 {
5305 	if (can_use_gui() && !strempty(default_param)) {
5306 		const char *c = default_param+2;
5307 		const building_tile_desc_t *tile = hausbauer_t::find_tile(c,0);
5308 		if(tile!=NULL) {
5309 			int rotation = (default_param[1]-'0') % tile->get_desc()->get_all_layouts();
5310 			cursor_area = tile->get_desc()->get_size(rotation);
5311 		}
5312 	}
5313 	return true;
5314 }
5315 
5316 
work(player_t * player,koord3d pos)5317 const char *tool_build_house_t::work( player_t *player, koord3d pos )
5318 {
5319 	koord k(pos.get_2d());
5320 
5321 	const grund_t* gr = welt->lookup_kartenboden(k);
5322 	if(gr==NULL) {
5323 		return "";
5324 	}
5325 
5326 	// Parsing parameter (if there)
5327 	const building_desc_t *desc = NULL;
5328 	if (!strempty(default_param)) {
5329 		const char *c = default_param+2;
5330 		const building_tile_desc_t *tile = hausbauer_t::find_tile(c,0);
5331 		if(tile) {
5332 			desc = tile->get_desc();
5333 		}
5334 	}
5335 	else {
5336 		desc = hausbauer_t::get_random_attraction( welt->get_timeline_year_month(), false, welt->get_climate( k ) );
5337 	}
5338 
5339 	if(desc==NULL) {
5340 		return "";
5341 	}
5342 	int rotation;
5343 	if(  !default_param || default_param[1]=='#'  ) {
5344 		rotation = simrand(desc->get_all_layouts());
5345 	}
5346 	else if(  default_param[1]=='A'  ) {
5347 		if(  desc->get_type()!=building_desc_t::attraction_land  &&  desc->get_type()!=building_desc_t::attraction_city  ) {
5348 			// auto rotation only valid for city buildings
5349 			rotation = stadt_t::orient_city_building( k, desc, desc->get_size() );
5350 			if(  rotation < 0 ) {
5351 				return NOTICE_UNSUITABLE_GROUND;
5352 			}
5353 		}
5354 		else {
5355 			rotation = simrand(desc->get_all_layouts());
5356 		}
5357 	}
5358 	else {
5359 		rotation = (default_param[1]-'0') % desc->get_all_layouts();
5360 	}
5361 
5362 	koord size = desc->get_size(rotation);
5363 
5364 	// process ignore climates switch
5365 	climate_bits cl = (default_param  &&  default_param[0]=='1') ? ALL_CLIMATES : desc->get_allowed_climate_bits();
5366 
5367 	bool hat_platz = welt->square_is_free( k, desc->get_x(rotation), desc->get_y(rotation), NULL, cl );
5368 	if(!hat_platz  &&  size.y!=size.x  &&  desc->get_all_layouts()>1  &&  (default_param==NULL  ||  default_param[1]=='#'  ||  default_param[1]=='A')) {
5369 		// try other rotation too ...
5370 		rotation = (rotation+1) % desc->get_all_layouts();
5371 		hat_platz = welt->square_is_free( k, desc->get_x(rotation), desc->get_y(rotation), NULL, cl );
5372 	}
5373 
5374 	// Place found...
5375 	if(hat_platz) {
5376 		player_t *gb_player = desc->is_city_building() ? NULL : welt->get_public_player();
5377 		gebaeude_t *gb = hausbauer_t::build(gb_player, gr->get_pos(), rotation, desc);
5378 		if(gb) {
5379 			// building successful
5380 			if(  desc->get_type()!=building_desc_t::attraction_land  &&  desc->get_type()!=building_desc_t::attraction_city  ) {
5381 				stadt_t *city = welt->find_nearest_city( k );
5382 				if(city) {
5383 					city->add_gebaeude_to_stadt(gb);
5384 				}
5385 			}
5386 			player_t::book_construction_costs(player, -desc->get_price(welt) * size.x * size.y, k, gb->get_waytype());
5387 			return NULL;
5388 		}
5389 	}
5390 	return NOTICE_UNSUITABLE_GROUND;
5391 }
5392 
5393 
5394 
5395 // show industry size in cursor (in known)
init(player_t *)5396 bool tool_build_land_chain_t::init( player_t * )
5397 {
5398 	if (can_use_gui() && !strempty(default_param)) {
5399 		const char *c = default_param+2;
5400 		while(*c  &&  *c++!=',') { /* do nothing */ }
5401 		const factory_desc_t *fab = factory_builder_t::get_desc(c);
5402 		if(fab==NULL) {
5403 			// wrong tool!
5404 			return false;
5405 		}
5406 		int rotation = (default_param[1]-'0') % fab->get_building()->get_all_layouts();
5407 		cursor_area = fab->get_building()->get_size(rotation);
5408 	}
5409 	return true;
5410 }
5411 
5412 /* builds a (if param=NULL random) industry chain starting here *
5413  * the parameter string is a follow:
5414  * 1#34,oelfeld
5415  * first letter: ignore climates
5416  * second letter: rotation (0,1,2,3,#=random)
5417  * next number is production value
5418  * finally industry name
5419  */
work(player_t * player,koord3d pos)5420 const char *tool_build_land_chain_t::work( player_t *player, koord3d pos )
5421 {
5422 	const grund_t* gr = welt->lookup_kartenboden(pos.get_2d());
5423 	if(gr==NULL) {
5424 		return "";
5425 	}
5426 
5427 	const factory_desc_t *fab = NULL;
5428 	if (!strempty(default_param)) {
5429 		const char *c = default_param+2;
5430 		while(*c  &&  *c++!=',') { /* do nothing */ }
5431 		fab = factory_builder_t::get_desc(c);
5432 	}
5433 	else {
5434 		fab = factory_builder_t::get_random_consumer( false, (climate_bits)(1 << welt->get_climate( pos.get_2d() )), welt->get_timeline_year_month() );
5435 	}
5436 
5437 	if(fab==NULL) {
5438 		return "";
5439 	}
5440 	int rotation = (default_param  &&  default_param[1]!='#') ? (default_param[1]-'0') % fab->get_building()->get_all_layouts() : simrand(fab->get_building()->get_all_layouts()-1);
5441 	koord size = fab->get_building()->get_size(rotation);
5442 
5443 	// process ignore climates switch
5444 	bool ignore_climates = default_param  &&  default_param[0]=='1';
5445 	climate_bits cl = ignore_climates ? ALL_CLIMATES : fab->get_building()->get_allowed_climate_bits();
5446 
5447 	bool hat_platz = false;
5448 	if(fab->get_placement()==factory_desc_t::Water) {
5449 		// at sea
5450 		hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) );
5451 
5452 		if(!hat_platz  &&  size.y!=size.x  &&  fab->get_building()->get_all_layouts()>1  &&  (default_param==NULL  ||  default_param[1]=='#')) {
5453 			// try other rotation too ...
5454 			rotation = (rotation+1) % fab->get_building()->get_all_layouts();
5455 			hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) );
5456 		}
5457 	}
5458 	else {
5459 		// and on solid ground
5460 		hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl );
5461 
5462 		if(!hat_platz  &&  size.y!=size.x  &&  fab->get_building()->get_all_layouts()>1  &&  (default_param==NULL  ||  default_param[1]=='#')) {
5463 			// try other rotation too ...
5464 			rotation = (rotation+1) % fab->get_building()->get_all_layouts();
5465 			hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl );
5466 		}
5467 	}
5468 
5469 	if(hat_platz) {
5470 		// eventually adjust production
5471 		sint32 initial_prod = -1;
5472 		if (!strempty(default_param)) {
5473 			initial_prod = welt->inverse_scale_with_month_length( atol(default_param+2) );
5474 		}
5475 
5476 		koord3d build_pos = gr->get_pos();
5477 		int count = factory_builder_t::build_link(NULL, fab, initial_prod, rotation, &build_pos, welt->get_public_player(), 10000, ignore_climates);
5478 
5479 		if(count>0) {
5480 			// at least one factory has been built
5481 			welt->get_viewport()->change_world_position( build_pos );
5482 			player_t::book_construction_costs(player, count * welt->get_settings().cst_multiply_found_industry, build_pos.get_2d(), ignore_wt);
5483 
5484 			// crossconnect all?
5485 			if (welt->get_settings().is_crossconnect_factories()) {
5486 				FOR(slist_tpl<fabrik_t*>, const f, welt->get_fab_list()) {
5487 					f->add_all_suppliers();
5488 				}
5489 			}
5490 			return NULL;
5491 		}
5492 	}
5493 	return NOTICE_UNSUITABLE_GROUND;
5494 }
5495 
5496 
5497 // show industry size in cursor (in known)
init(player_t *)5498 bool tool_city_chain_t::init( player_t * )
5499 {
5500 	if (can_use_gui() && !strempty(default_param)) {
5501 		const char *c = default_param+2;
5502 		while(*c  &&  *c++!=',') { /* do nothing */ }
5503 		const factory_desc_t *fab = factory_builder_t::get_desc(c);
5504 		if(fab==NULL) {
5505 			// wrong tool!
5506 			return false;
5507 		}
5508 		int rotation = (default_param[1]-'0') % fab->get_building()->get_all_layouts();
5509 		cursor_area = fab->get_building()->get_size(rotation);
5510 	}
5511 	return true;
5512 }
5513 
5514 /* builds a industry chain in the next town
5515  * defaukt_param see previous function
5516  */
work(player_t * player,koord3d pos)5517 const char *tool_city_chain_t::work( player_t *player, koord3d pos )
5518 {
5519 	const grund_t* gr = welt->lookup_kartenboden(pos.get_2d());
5520 	if(gr==NULL) {
5521 		return "";
5522 	}
5523 
5524 	const factory_desc_t *fab = NULL;
5525 	if (!strempty(default_param)) {
5526 		const char *c = default_param+2;
5527 		while(*c  &&  *c++!=',') { /* do nothing */ }
5528 		fab = factory_builder_t::get_desc(c);
5529 	}
5530 	else {
5531 		fab = factory_builder_t::get_random_consumer( false, (climate_bits)(1 << welt->get_climate( pos.get_2d() )), welt->get_timeline_year_month() );
5532 	}
5533 
5534 	if(fab==NULL) {
5535 		return "";
5536 	}
5537 
5538 	// eventually adjust production
5539 	sint32 initial_prod = -1;
5540 	if (!strempty(default_param)) {
5541 		initial_prod = welt->inverse_scale_with_month_length( atol(default_param+2) );
5542 	}
5543 
5544 	// process ignore climates switch
5545 	bool ignore_climates = default_param  &&  default_param[0]=='1';
5546 
5547 	pos = gr->get_pos();
5548 	int count = factory_builder_t::build_link(NULL, fab, initial_prod, 0, &pos, welt->get_public_player(), 10000, ignore_climates);
5549 	if(count>0) {
5550 		// at least one factory has been built
5551 		welt->get_viewport()->change_world_position( pos );
5552 
5553 		// crossconnect all?
5554 		if (welt->get_settings().is_crossconnect_factories()) {
5555 			FOR(slist_tpl<fabrik_t*>, const f, welt->get_fab_list()) {
5556 				f->add_all_suppliers();
5557 			}
5558 		}
5559 		// ain't going to be cheap
5560 		player_t::book_construction_costs(player, count * welt->get_settings().cst_multiply_found_industry, pos.get_2d(), ignore_wt);
5561 		return NULL;
5562 	}
5563 	return NOTICE_UNSUITABLE_GROUND;
5564 }
5565 
5566 
5567 
5568 // show industry size in cursor (must be known!)
init(player_t *)5569 bool tool_build_factory_t::init( player_t * )
5570 {
5571 	if (can_use_gui() && !strempty(default_param)) {
5572 		const char *c = default_param+2;
5573 		while(*c  &&  *c++!=',') { /* do nothing */ }
5574 		const factory_desc_t *fab = factory_builder_t::get_desc(c);
5575 		if(fab==NULL) {
5576 			// wrong tool!
5577 			return false;
5578 		}
5579 		int rotation = (default_param[1]-'0') % fab->get_building()->get_all_layouts();
5580 		cursor_area = fab->get_building()->get_size(rotation);
5581 		return true;
5582 	}
5583 	return true;
5584 }
5585 
5586 /* builds an industry next to the cursor (default_param see above) */
work(player_t * player,koord3d pos)5587 const char *tool_build_factory_t::work( player_t *player, koord3d pos )
5588 {
5589 	const grund_t* gr = welt->lookup_kartenboden(pos.get_2d());
5590 	if(gr==NULL) {
5591 		return "";
5592 	}
5593 
5594 	const factory_desc_t *fab = NULL;
5595 	if (!strempty(default_param)) {
5596 		const char *c = default_param+2;
5597 		while(*c  &&  *c++!=',') { /* do nothing */ }
5598 		fab = factory_builder_t::get_desc(c);
5599 	}
5600 	else {
5601 		fab = factory_builder_t::get_random_consumer( false, (climate_bits)(1 << welt->get_climate( pos.get_2d() )), welt->get_timeline_year_month() );
5602 	}
5603 
5604 	if(fab==NULL) {
5605 		return "";
5606 	}
5607 	int rotation = (default_param  &&  default_param[1]!='#') ? (default_param[1]-'0') % fab->get_building()->get_all_layouts() : simrand(fab->get_building()->get_all_layouts());
5608 	koord size = fab->get_building()->get_size(rotation);
5609 
5610 	// process ignore climates switch
5611 	climate_bits cl = (default_param  &&  default_param[0]=='1') ? ALL_CLIMATES : fab->get_building()->get_allowed_climate_bits();
5612 
5613 	bool hat_platz = false;
5614 	if(fab->get_placement()==factory_desc_t::Water) {
5615 		// at sea
5616 		hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) );
5617 
5618 		if(!hat_platz  &&  size.y!=size.x  &&  fab->get_building()->get_all_layouts()>1  &&  (default_param==NULL  ||  default_param[1]=='#')) {
5619 			// try other rotation too ...
5620 			rotation = (rotation+1) % fab->get_building()->get_all_layouts();
5621 			hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) );
5622 		}
5623 	}
5624 	else {
5625 		// and on solid ground
5626 		hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl );
5627 
5628 		if(!hat_platz  &&  size.y!=size.x  &&  fab->get_building()->get_all_layouts()>1  &&  (default_param==NULL  ||  default_param[1]=='#')) {
5629 			// try other rotation too ...
5630 			rotation = (rotation+1) % fab->get_building()->get_all_layouts();
5631 			hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl );
5632 		}
5633 	}
5634 
5635 	if(hat_platz) {
5636 		// eventually adjust production
5637 		sint32 initial_prod = -1;
5638 		if (!strempty(default_param)) {
5639 			initial_prod = welt->inverse_scale_with_month_length( atol(default_param+2) );
5640 		}
5641 
5642 		fabrik_t *f = factory_builder_t::build_factory(NULL, fab, initial_prod, rotation, gr->get_pos(), welt->get_public_player());
5643 		if(f) {
5644 			// at least one factory has been built
5645 			welt->get_viewport()->change_world_position( pos );
5646 			player_t::book_construction_costs(player, welt->get_settings().cst_multiply_found_industry, pos.get_2d(), ignore_wt);
5647 
5648 			// crossconnect all?
5649 			if (welt->get_settings().is_crossconnect_factories()) {
5650 				FOR(slist_tpl<fabrik_t*>, const f, welt->get_fab_list()) {
5651 					f->add_all_suppliers();
5652 				}
5653 			}
5654 			return NULL;
5655 		}
5656 	}
5657 	return NOTICE_UNSUITABLE_GROUND;
5658 }
5659 
5660 
5661 
5662 /**	link tool: links products of factory one with factory two (if possible)
5663  */
get_marker_image()5664 image_id tool_link_factory_t::get_marker_image()
5665 {
5666 	return cursor;
5667 }
5668 
5669 
is_valid_pos(player_t *,const koord3d & pos,const char * & error,const koord3d &)5670 uint8 tool_link_factory_t::is_valid_pos( player_t *, const koord3d &pos, const char *&error, const koord3d & )
5671 {
5672 	fabrik_t *fab = fabrik_t::get_fab( pos.get_2d() );
5673 	if (fab == NULL) {
5674 		error = "";
5675 		return 0;
5676 	}
5677 	return 2;
5678 }
5679 
5680 
do_work(player_t *,const koord3d & start,const koord3d & pos)5681 const char *tool_link_factory_t::do_work( player_t *, const koord3d &start, const koord3d &pos )
5682 {
5683 	fabrik_t *last_fab = fabrik_t::get_fab( start.get_2d() );
5684 	fabrik_t *fab = fabrik_t::get_fab( pos.get_2d() );
5685 
5686 	if(fab!=NULL  &&  last_fab!=NULL  &&  last_fab!=fab) {
5687 		// It's a factory
5688 		if(!is_ctrl_pressed()) {
5689 			if(fab->add_supplier(last_fab) || last_fab->add_supplier(fab)) {
5690 				//ok! they are connected
5691 				return NULL;
5692 			}
5693 		}
5694 		else {
5695 			// remove connections
5696 			fab->rem_supplier(last_fab->get_pos().get_2d());
5697 			fab->rem_lieferziel(last_fab->get_pos().get_2d());
5698 			last_fab->rem_supplier(fab->get_pos().get_2d());
5699 			last_fab->rem_lieferziel(fab->get_pos().get_2d());
5700 			return NULL;
5701 		}
5702 	}
5703 	return "";
5704 }
5705 
5706 
5707 /* builds company headquarters
5708  * @author prissi
5709  */
next_level(const player_t * player) const5710 const building_desc_t *tool_headquarter_t::next_level( const player_t *player ) const
5711 {
5712 	return hausbauer_t::get_headquarters(player->get_headquarter_level(), welt->get_timeline_year_month());
5713 }
5714 
get_tooltip(const player_t * player) const5715 const char* tool_headquarter_t::get_tooltip(const player_t *player) const
5716 {
5717 	if (building_desc_t const* const desc = next_level(player)) {
5718 		settings_t  const& s      = welt->get_settings();
5719 		char const* const  tip    = player->get_headquarter_level() == 0 ? "build HQ" : "upgrade HQ";
5720 		sint64      const  factor = desc->get_x() * desc->get_y();
5721 		return tooltip_with_price_maintenance(welt, tip, -factor * desc->get_price(welt), factor * desc->get_level() * s.maint_building);
5722 	}
5723 	return NULL;
5724 }
5725 
init(player_t * player)5726 bool tool_headquarter_t::init( player_t *player )
5727 {
5728 	// do no use this, if there is no next level to build ...
5729 	const building_desc_t *desc = next_level(player);
5730 	if (desc) {
5731 		if (can_use_gui()) {
5732 			const int rotation = 0;
5733 			cursor_area = desc->get_size(rotation);
5734 		}
5735 		return true;
5736 	}
5737 	return false;
5738 }
5739 
5740 
work(player_t * player,koord3d pos)5741 const char *tool_headquarter_t::work( player_t *player, koord3d pos )
5742 {
5743 	bool ok=false;
5744 	bool built = false;
5745 DBG_MESSAGE("tool_headquarter()", "building headquarters at (%d,%d)", pos.x, pos.y);
5746 
5747 	const building_desc_t* desc = next_level(player);
5748 	if(desc==NULL) {
5749 		// no further headquarters level
5750 		dbg->message( "tool_headquarter()", "Already at maximum level!" );
5751 		return "";
5752 	}
5753 
5754 	// check funds
5755 	koord size = desc->get_size();
5756 	sint64 const cost = -desc->get_price(welt) * size.x * size.y;
5757 	if(  !player->can_afford(cost)  ) {
5758 		return NOTICE_INSUFFICIENT_FUNDS;
5759 	}
5760 
5761 	koord k(pos.get_2d());
5762 	grund_t *gr = welt->lookup_kartenboden(k);
5763 
5764 	if(gr) {
5765 		gebaeude_t *hq = NULL;
5766 		// check for current head quarter
5767 		koord previous = player->get_headquarter_pos();
5768 		if(previous!=koord::invalid) {
5769 			grund_t *gr_hq = welt->lookup_kartenboden(previous);
5770 			gebaeude_t *prev_hq = gr_hq->find<gebaeude_t>();
5771 			// check if upgrade should be built at same place as current one
5772 			gebaeude_t *gb = gr->find<gebaeude_t>();
5773 			if (gb  &&  gb->get_owner()==player  &&  prev_hq->get_tile()->get_desc()==gb->get_tile()->get_desc()) {
5774 				const building_desc_t* prev_desc = prev_hq->get_tile()->get_desc();
5775 				// check if sizes fit
5776 				uint8 prev_layout = prev_hq->get_tile()->get_layout();
5777 				uint8 layout =  prev_layout % desc->get_all_layouts();
5778 				koord size = desc->get_size(layout);
5779 				if (prev_desc->get_size(prev_layout) == size) {
5780 					// check for same tile structure
5781 					ok = true;
5782 					for (sint16 x=0; x<size.x  &&  ok; x++) {
5783 						for (sint16 y=0; y<size.y  &&  ok; y++) {
5784 							ok = (prev_desc->get_tile(prev_layout, x, y)==NULL)==(desc->get_tile(layout, x, y)==NULL);
5785 						}
5786 					}
5787 					hq = gb;
5788 					if(  ok  ) {
5789 						// upgrade the tiles
5790 						koord k_hq = k - gb->get_tile()->get_offset();
5791 						for(  sint16 x = 0;  x < size.x;  x++  ) {
5792 							for(  sint16 y = 0;  y < size.y;  y++  ) {
5793 								if(  const building_tile_desc_t *tile = desc->get_tile(layout, x, y)  ) {
5794 									if(  grund_t *gr2 = welt->lookup_kartenboden(k_hq + koord(x, y))  ) {
5795 										if(  gebaeude_t *gb = gr2->find<gebaeude_t>()  ) {
5796 											if(  gb  &&  gb->get_owner() == player  &&  prev_desc == gb->get_tile()->get_desc()  ) {
5797 												player_t::add_maintenance( player, -prev_desc->get_maintenance(welt), prev_desc->get_finance_waytype() );
5798 												gb->set_tile( tile, true );
5799 												gb->calc_image();
5800 												player_t::add_maintenance( player, desc->get_maintenance(welt), desc->get_finance_waytype() );
5801 											}
5802 										}
5803 									}
5804 								}
5805 							}
5806 						}
5807 						built = true;
5808 					}
5809 				}
5810 			}
5811 			// did not upgrade old one, need to remove it
5812 			if(  !built  ) {
5813 				// remove previous one
5814 				hausbauer_t::remove( player, prev_hq );
5815 				// resize cursor
5816 				init(player);
5817 			}
5818 		}
5819 
5820 
5821 		// build new one
5822 		if (!built) {
5823 			int rotate = 0;
5824 
5825 			if(welt->square_is_free(k, size.x, size.y, NULL, desc->get_allowed_climate_bits())) {
5826 				ok = true;
5827 			}
5828 			if(!ok  &&  desc->get_all_layouts()>1  &&  size.y != size.x  &&  welt->square_is_free(k, size.y, size.x, NULL, desc->get_allowed_climate_bits())) {
5829 				rotate = 1;
5830 				ok = true;
5831 			}
5832 
5833 			if(ok) {
5834 				// then built it
5835 				hq = hausbauer_t::build(player, gr->get_pos(), rotate, desc, NULL);
5836 				stadt_t *city = welt->find_nearest_city( k );
5837 				if(city) {
5838 					city->add_gebaeude_to_stadt( hq );
5839 				}
5840 				built = true;
5841 			}
5842 			else {
5843 				return NOTICE_UNSUITABLE_GROUND;
5844 			}
5845 		}
5846 
5847 
5848 		if(  built  ) {
5849 			// sometimes those are not correct after rotation ...
5850 			player->add_headquarter( desc->get_extra() + 1, hq->get_pos().get_2d() - hq->get_tile()->get_offset() );
5851 			player_t::book_construction_costs(player,  cost, k, ignore_wt);
5852 			// tell the world of it ...
5853 			cbuffer_t buf;
5854 			buf.printf( translator::translate("%s s\nheadquarter now\nat (%i,%i)."), player->get_name(), pos.x, pos.y );
5855 			welt->get_message()->add_message( buf, k, message_t::ai, PLAYER_FLAG|player->get_player_nr(), hq->get_tile()->get_background(0,0,0) );
5856 			// reset to query tool, since costly relocations should be avoided
5857 			if(can_use_gui()  &&  player == welt->get_active_player()) {
5858 				welt->set_tool( tool_t::general_tool[TOOL_QUERY], player );
5859 			}
5860 			return NULL;
5861 		}
5862 	}
5863 	return "";
5864 }
5865 
work(player_t *,koord3d)5866 const char *tool_lock_game_t::work( player_t *, koord3d )
5867 {
5868 	// tool can never be executed in network mode
5869 	if (env_t::networkmode) {
5870 		return "";
5871 	}
5872 	// as the result depends on the local locked state of public player
5873 	if (welt->get_public_player()->is_locked() || !welt->get_settings().get_allow_player_change()) {
5874 		return "Only public player can lock games!";
5875 	}
5876 	welt->clear_player_password_hashes();
5877 	if(  !welt->get_public_player()->is_locked() ) {
5878 		return "In order to lock the game, you have to protect the public player by password!";
5879 	}
5880 	destroy_all_win( true );
5881 	welt->switch_active_player( 0, true );
5882 	welt->get_settings().set_allow_player_change(false);
5883 	welt->set_tool( general_tool[TOOL_QUERY], welt->get_player(0) );
5884 	return NULL;
5885 }
5886 
5887 
work(player_t * player,koord3d pos)5888 const char *tool_add_citycar_t::work( player_t *player, koord3d pos )
5889 {
5890 	if( private_car_t::list_empty() ) {
5891 		// No citycar
5892 		return "";
5893 	}
5894 	grund_t *gr = tool_intern_koord_to_weg_grund( player, welt, pos, road_wt );
5895 
5896 	if(  gr != NULL  &&  ribi_t::is_twoway(gr->get_weg_ribi_unmasked(road_wt))  &&  gr->find<private_car_t>() == NULL) {
5897 		// add citycar
5898 		private_car_t* vt = new private_car_t(gr, koord::invalid);
5899 		gr->obj_add(vt);
5900 		welt->sync.add(vt);
5901 		return NULL;
5902 	}
5903 	return "";
5904 }
5905 
5906 
is_valid_pos(player_t *,const koord3d &,const char * &,const koord3d &)5907 uint8 tool_forest_t::is_valid_pos( player_t *, const koord3d &, const char *&, const koord3d & )
5908 {
5909 	// do really nothing ...
5910 	return 2;
5911 }
5912 
5913 
mark_tiles(player_t *,const koord3d & start,const koord3d & end)5914 void tool_forest_t::mark_tiles(  player_t *, const koord3d &start, const koord3d &end )
5915 {
5916 	koord k1, k2;
5917 	k1.x = start.x < end.x ? start.x : end.x;
5918 	k1.y = start.y < end.y ? start.y : end.y;
5919 	k2.x = start.x + end.x - k1.x;
5920 	k2.y = start.y + end.y - k1.y;
5921 	koord k;
5922 	for(  k.x = k1.x;  k.x <= k2.x;  k.x++  ) {
5923 		for(  k.y = k1.y;  k.y <= k2.y;  k.y++  ) {
5924 			grund_t *gr = welt->lookup_kartenboden( k );
5925 
5926 			zeiger_t *marker = new zeiger_t(gr->get_pos(), NULL );
5927 
5928 			const uint8 grund_hang = gr->get_grund_hang();
5929 			const uint8 weg_hang = gr->get_weg_hang();
5930 			const uint8 hang = max( corner_sw(grund_hang), corner_sw(weg_hang)) +
5931 					3 * max( corner_se(grund_hang), corner_se(weg_hang)) +
5932 					9 * max( corner_ne(grund_hang), corner_ne(weg_hang)) +
5933 					27 * max( corner_nw(grund_hang), corner_nw(weg_hang));
5934 			uint8 back_hang = (hang % 3) + 3 * ((uint8)(hang / 9)) + 27;
5935 			marker->set_foreground_image( ground_desc_t::marker->get_image( grund_hang % 27 ) );
5936 			marker->set_image( ground_desc_t::marker->get_image( back_hang ) );
5937 
5938 			marker->mark_image_dirty( marker->get_image(), 0 );
5939 			gr->obj_add( marker );
5940 			marked.insert( marker );
5941 		}
5942 	}
5943 }
5944 
5945 
do_work(player_t * player,const koord3d & start,const koord3d & end)5946 const char *tool_forest_t::do_work( player_t *player, const koord3d &start, const koord3d &end )
5947 {
5948 	koord wh, nw;
5949 	wh.x = abs(end.x-start.x)+1;
5950 	wh.y = abs(end.y-start.y)+1;
5951 	nw.x = min(start.x, end.x)+(wh.x/2);
5952 	nw.y = min(start.y, end.y)+(wh.y/2);
5953 
5954 	sint64 costs = baum_t::create_forest( nw, wh );
5955 	player_t::book_construction_costs(player, costs * welt->get_settings().cst_remove_tree, end.get_2d(), ignore_wt);
5956 
5957 	return NULL;
5958 }
5959 
5960 
get_marker_image()5961 image_id tool_stop_mover_t::get_marker_image()
5962 {
5963 	return cursor;
5964 }
5965 
5966 
read_start_position(player_t * player,const koord3d & pos)5967 void tool_stop_mover_t::read_start_position(player_t *player, const koord3d &pos)
5968 {
5969 	waytype[0] = invalid_wt;
5970 	waytype[1] = invalid_wt;
5971 	last_halt = halthandle_t();
5972 
5973 	grund_t *bd = welt->lookup(pos);
5974 	if (bd==NULL) {
5975 		return;
5976 	}
5977 	// now assign waytypes
5978 	if(bd->is_water()) {
5979 		waytype[0] = water_wt;
5980 	}
5981 	else {
5982 		waytype[0] = bd->get_weg_nr(0)->get_waytype();
5983 		if(bd->get_weg_nr(1)) {
5984 			waytype[1] = bd->get_weg_nr(1)->get_waytype();
5985 		}
5986 	}
5987 	// .. and halt
5988 	last_halt = haltestelle_t::get_halt(pos,player);
5989 }
5990 
5991 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d & start)5992 uint8 tool_stop_mover_t::is_valid_pos(  player_t *player, const koord3d &pos, const char *&error, const koord3d &start)
5993 {
5994 	grund_t *bd = welt->lookup(pos);
5995 	if (bd==NULL) {
5996 		error = "";
5997 		return 0;
5998 	}
5999 	// check halt ownership
6000 	halthandle_t h = haltestelle_t::get_halt(pos,player);
6001 	if(  h.is_bound()  &&  !player_t::check_owner( player, h->get_owner() )  ) {
6002 		error = "Das Feld gehoert\neinem anderen Spieler\n";
6003 		return 0;
6004 	}
6005 	// check for halt on the tile
6006 	if(  h.is_bound()  &&  !(bd->is_halt()  ||  (h->get_station_type()&haltestelle_t::dock  &&  bd->is_water())  )  ) {
6007 		error = NOTICE_UNSUITABLE_GROUND;
6008 		return 0;
6009 	}
6010 
6011 	if (start==koord3d::invalid) {
6012 		// check for existing ways
6013 		if (bd->is_water()  ||  bd->hat_wege()) {
6014 			return 2;
6015 		}
6016 		else {
6017 			error = NOTICE_UNSUITABLE_GROUND;
6018 			return 0;
6019 		}
6020 	}
6021 	else {
6022 		// read conditions at start point
6023 		read_start_position(player, start);
6024 		// check halts vs waypoints
6025 		if(h.is_bound() ^ last_halt.is_bound()) {
6026 			error = "Can only move from halt to halt or waypoint to waypoint.";
6027 			return 0;
6028 		}
6029 		// check waytypes
6030 		if(  (waytype[0] == water_wt  &&  bd->is_water())  ||  bd->hat_weg(waytype[0])  ||  bd->hat_weg(waytype[1])  ) {
6031 			// ok
6032 			return 2;
6033 		}
6034 		else {
6035 			error = NOTICE_UNSUITABLE_GROUND;
6036 			return 0;
6037 		}
6038 	}
6039 }
6040 
do_work(player_t * player,const koord3d & last_pos,const koord3d & pos)6041 const char *tool_stop_mover_t::do_work( player_t *player, const koord3d &last_pos, const koord3d &pos)
6042 {
6043 	// read conditions at start point
6044 	read_start_position(player, last_pos);
6045 
6046 	// second click
6047 	grund_t *bd = welt->lookup(pos);
6048 	halthandle_t h = haltestelle_t::get_halt(pos,player);
6049 
6050 	if (bd) {
6051 		const halthandle_t new_halt = h;
6052 		// depending on the waytype we simply build replacements lists
6053 		// in the worst case we have to iterate over all tiles twice ...
6054 		for(  uint i=0;  i<2;  i++  ) {
6055 			const waytype_t wt = waytype[i];
6056 			slist_tpl <koord3d>old_platform;
6057 
6058 			if(bd->is_water()) {
6059 				if(wt!=water_wt) {
6060 					break;
6061 				}
6062 			}
6063 			else if(!bd->hat_weg(wt)) {
6064 				continue;
6065 			}
6066 			// platform, stop or just tile moving?
6067 			const bool catch_all_halt = (wt==water_wt  ||  wt==air_wt)  &&  last_halt.is_bound();
6068 			if(!last_halt.is_bound()) {
6069 				old_platform.append(last_pos);
6070 			}
6071 			else if(!catch_all_halt) {
6072 				// builds a coordinate list
6073 				if(wt==road_wt) {
6074 					old_platform.append(last_pos);
6075 				}
6076 				else {
6077 					// all connected tiles for start pos
6078 					uint8 ribi = welt->lookup(last_pos)->get_weg_ribi_unmasked(wt);
6079 					koord delta = ribi_t::is_straight_ns(ribi) ? koord(0,1) : koord(1,0);
6080 					koord3d start_pos=last_pos;
6081 					while(ribi&12) {
6082 						koord3d test_pos = start_pos+delta;
6083 						grund_t *gr = welt->lookup(test_pos);
6084 						if(!gr  ||  !gr->is_halt()  ||  (ribi=gr->get_weg_ribi_unmasked(wt))==0) {
6085 							break;
6086 						}
6087 						start_pos = test_pos;
6088 					}
6089 					// now add all of them
6090 					while(ribi&3) {
6091 						koord3d test_pos = start_pos-delta;
6092 						grund_t *gr = welt->lookup(test_pos);
6093 						old_platform.append(start_pos);
6094 						if(!gr  ||  !gr->is_halt()  ||  (ribi=gr->get_weg_ribi_unmasked(wt))==0) {
6095 							break;
6096 						}
6097 						start_pos = test_pos;
6098 					}
6099 				}
6100 			}
6101 
6102 			// first, check convoi without line
6103 			FOR(vector_tpl<convoihandle_t>, const cnv, welt->convoys()) {
6104 				// check line and owner
6105 				if(!cnv->get_line().is_bound()  &&  cnv->get_owner()==player) {
6106 					schedule_t *schedule = cnv->get_schedule();
6107 					// check waytype
6108 					if(schedule  &&  schedule->is_stop_allowed(bd)) {
6109 						bool updated = false;
6110 						FOR(minivec_tpl<schedule_entry_t>, & k, schedule->entries) {
6111 							if ((catch_all_halt && haltestelle_t::get_halt( k.pos, cnv->get_owner()) == last_halt) ||
6112 									old_platform.is_contained(k.pos)) {
6113 								k.pos   = pos;
6114 								updated = true;
6115 							}
6116 						}
6117 						if(updated) {
6118 							schedule->cleanup();
6119 							// Knightly : remove lineless convoy from old stop
6120 							if(  last_halt.is_bound()  ) {
6121 								last_halt->remove_convoy(cnv);
6122 							}
6123 							// Knightly : register lineless convoy at new stop
6124 							if(  new_halt.is_bound()  ) {
6125 								new_halt->add_convoy(cnv);
6126 							}
6127 							if(  !schedule->is_editing_finished()  ) {
6128 								// schedule is not owned by schedule window ...
6129 								// ... thus we can set this schedule
6130 								cnv->set_schedule(schedule);
6131 								// otherwise the schedule window will reset it
6132 							}
6133 						}
6134 					}
6135 				}
6136 			}
6137 			// next, check lines serving old_halt (no owner check needed for own lines ...
6138 			vector_tpl<linehandle_t>lines;
6139 			player->simlinemgmt.get_lines(simline_t::line,&lines);
6140 			FOR(vector_tpl<linehandle_t>, const line, lines) {
6141 				schedule_t *schedule = line->get_schedule();
6142 				// check waytype
6143 				if(schedule->is_stop_allowed(bd)) {
6144 					bool updated = false;
6145 					FOR(minivec_tpl<schedule_entry_t>, & k, schedule->entries) {
6146 						// ok!
6147 						if ((catch_all_halt && haltestelle_t::get_halt( k.pos, line->get_owner()) == last_halt) ||
6148 								old_platform.is_contained(k.pos)) {
6149 							k.pos   = pos;
6150 							updated = true;
6151 						}
6152 					}
6153 					// update line
6154 					if(updated) {
6155 						schedule->cleanup();
6156 						// remove line from old stop is needed at here
6157 						if(last_halt.is_bound()) {
6158 							last_halt->remove_line(line);
6159 						}
6160 						player->simlinemgmt.update_line(line);
6161 					}
6162 				}
6163 			}
6164 		}
6165 		// since factory connections may have changed
6166 		welt->set_schedule_counter();
6167 	}
6168 	return NULL;
6169 }
6170 
6171 
get_tooltip(player_t const *) const6172 char const* tool_daynight_level_t::get_tooltip(player_t const*) const
6173 {
6174 	if (!strempty(default_param)) {
6175 		if(default_param[0]=='+'  ||  default_param[0]=='-') {
6176 			sprintf(toolstr, "%s %s",
6177 			translator::translate("1LIGHT_CHOOSE"),
6178 			&default_param[0]);
6179 			return toolstr;
6180 		}
6181 		else {
6182 			return translator::translate("Toggle day/night view");
6183 		}
6184 	}
6185 	else {
6186 		return "";
6187 	}
6188 }
6189 
init(player_t *)6190 bool tool_daynight_level_t::init( player_t * ) {
6191 	if(grund_t::underground_mode==grund_t::ugm_all  ||  env_t::night_shift) {
6192 		return false;
6193 	}
6194 	if (!strempty(default_param)) {
6195 		if(default_param[0]=='+'  &&  env_t::daynight_level > 0) {
6196 			// '+': fade in one level
6197 			env_t::daynight_level = env_t::daynight_level-1;
6198 		}
6199 		else if (default_param[0]=='-') {
6200 			// '-': fade out one level
6201 			env_t::daynight_level = env_t::daynight_level+1;
6202 		}
6203 		else {
6204 			// number: toggle number/0. 4 or 5 is good for night
6205 			const sint8 level = atoi(default_param);
6206 			env_t::daynight_level = (env_t::daynight_level==0) ? level : 0;
6207 		}
6208 	}
6209 	return false;
6210 }
6211 
6212 
6213 /* make all tiles of this player a public stop
6214  * if this player is public, make all connected tiles a public stop */
init(player_t *)6215 bool tool_make_stop_public_t::init( player_t * )
6216 {
6217 	win_set_static_tooltip( NULL );
6218 	return true;
6219 }
6220 
get_tooltip(const player_t *) const6221 const char* tool_make_stop_public_t::get_tooltip(const player_t *) const
6222 {
6223 	sprintf(toolstr, translator::translate("Make way or stop public (will join with neighbours), %i times maintainance"), welt->get_settings().cst_make_public_months);
6224 	return toolstr;
6225 }
6226 
move(player_t * player,uint16,koord3d p)6227 const char *tool_make_stop_public_t::move( player_t *player, uint16, koord3d p )
6228 {
6229 	// queue tool for network
6230 	if (env_t::networkmode) {
6231 		nwc_tool_t *nwc = new nwc_tool_t(player, this, p, welt->get_steps(), welt->get_map_counter(), false);
6232 		network_send_server(nwc);
6233 		return NULL;
6234 	}
6235 
6236 	return work( player, p );
6237 }
6238 
work(player_t * player,koord3d p)6239 const char *tool_make_stop_public_t::work( player_t *player, koord3d p )
6240 {
6241 	// target halt must exist
6242 	halthandle_t halt = haltestelle_t::get_halt(p,player);
6243 	if(  !halt.is_bound()  ) {
6244 		return NOTICE_UNSUITABLE_GROUND;
6245 	}
6246 
6247 	// check funds
6248 	sint64 workcost = -welt->scale_with_month_length(halt->calc_maintenance() * welt->get_settings().cst_make_public_months);
6249 
6250 	// check waycost and soem forbidden cases too
6251 	FOR(slist_tpl<haltestelle_t::tile_t>, const& i, halt->get_tiles()) {
6252 		// make way public if any suitable
6253 		for(  int j=0;  j<2;  j++  ) {
6254 			if(  weg_t *w=i.grund->get_weg_nr(0)  ) {
6255 				if(  w->get_owner() != welt->get_public_player()  ) {
6256 					// no public ways?
6257 					if(  welt->get_settings().get_disable_make_way_public()  ) {
6258 						return NOTICE_DISABLED_PUBLIC_WAY;
6259 					}
6260 					// no public way with signs
6261 					if(  w->has_sign()  ) {
6262 						return NOTICE_UNSUITABLE_GROUND;
6263 					}
6264 					// compute maintainance cost
6265 					sint32 cost = w->get_desc()->get_maintenance();
6266 					// tunnel cost overwrites way cost
6267 					if(  tunnel_t *t = i.grund->find<tunnel_t>()  ) {
6268 						cost = t->get_desc()->get_maintenance();
6269 					}
6270 					workcost -= welt->scale_with_month_length(cost * welt->get_settings().cst_make_public_months);
6271 					// not making ways public on bridges
6272 					if(  i.grund->get_typ()==grund_t::brueckenboden  ) {
6273 						return NOTICE_UNSUITABLE_GROUND;
6274 					}
6275 				}
6276 			}
6277 		}
6278 	}
6279 
6280 	if(  !player->can_afford(workcost)  ) {
6281 		return NOTICE_INSUFFICIENT_FUNDS;
6282 	}
6283 
6284 	// now find an adjacent stop
6285 	vector_tpl<halthandle_t>checked_halts;
6286 	checked_halts.append(halt);
6287 	halthandle_t merge_to;
6288 	FOR(slist_tpl<haltestelle_t::tile_t>, const& i, halt->get_tiles()) {
6289 		const koord pos = i.grund->get_pos().get_2d();
6290 		planquadrat_t *pl = welt->access( pos );
6291 		for(  int i=0;  i<pl->get_haltlist_count();  i++  ) {
6292 			halthandle_t h = pl->get_haltlist()[i];
6293 			if(  !checked_halts.is_contained(h)  &&  h->get_owner()==welt->get_public_player()  ) {
6294 				koord testpos = h->get_ground_closest_to( pos )->get_pos().get_2d();
6295 				if(  abs(pos.x-testpos.x) <= 1  &&  abs(pos.y-testpos.y) <= 1  ) {
6296 					merge_to = h;
6297 					break;
6298 				}
6299 			}
6300 		}
6301 		if(  merge_to.is_bound()  ) {
6302 			break;
6303 		}
6304 	}
6305 
6306 	// change ownership
6307 	halt->change_owner( welt->get_public_player() );
6308 	halt->merge_halt( merge_to );
6309 
6310 	return NULL;
6311 }
6312 
6313 
6314 /* merge stop */
get_marker_image()6315 image_id tool_merge_stop_t::get_marker_image()
6316 {
6317 	return cursor;
6318 }
6319 
is_valid_pos(player_t * player,const koord3d & pos,const char * & error,const koord3d &)6320 uint8 tool_merge_stop_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d &)
6321 {
6322 	grund_t *bd = welt->lookup(pos);
6323 	if (bd==NULL) {
6324 		error = "";
6325 		return 0;
6326 	}
6327 
6328 	// check halt ownership
6329 	halthandle_t h = haltestelle_t::get_halt(pos,player);
6330 	if(  h.is_bound()  ) {
6331 		//  allow to merge two public stops too
6332 		// so no need to check for ownership
6333 
6334 		// check for halt on the tile
6335 		if(  bd->is_halt()  ||  (h->get_station_type()&haltestelle_t::dock  &&  bd->is_water())  ) {
6336 			return 2;
6337 		}
6338 	}
6339 
6340 	// not a halt at all ...
6341 	error = NOTICE_UNSUITABLE_GROUND;
6342 	return 0;
6343 }
6344 
mark_tiles(player_t * player,const koord3d & start,const koord3d & end)6345 void tool_merge_stop_t::mark_tiles(  player_t *player, const koord3d &start, const koord3d &end )
6346 {
6347 	halt_be_merged_from = haltestelle_t::get_halt(start,player);
6348 	halt_be_merged_to = haltestelle_t::get_halt(end,player);
6349 	sint64 workcost = 0;
6350 	uint32 distance = 0x7FFFFFFFu;
6351 
6352 	FOR(slist_tpl<haltestelle_t::tile_t>, const& i, halt_be_merged_from->get_tiles()) {
6353 		FOR(slist_tpl<haltestelle_t::tile_t>, const& j, halt_be_merged_to->get_tiles()) {
6354 			uint32 dist = koord_distance( i.grund->get_pos(), j.grund->get_pos() );
6355 			if(  dist < distance  ) {
6356 				distance = dist;
6357 				if(  distance <= 1  ) {
6358 					break;
6359 				}
6360 			}
6361 		}
6362 		if(  distance <= 1  ) {
6363 			break;
6364 		}
6365 	}
6366 
6367 	if(  distance  < welt->get_settings().allow_merge_distant_halt  ) {
6368 		distance = clamp(distance,2,33)-2;
6369 		workcost = welt->scale_with_month_length( (1<<distance) * welt->get_settings().cst_multiply_merge_halt );
6370 		win_set_static_tooltip( tooltip_with_price("Building costs estimates", workcost) );
6371 	}
6372 	else {
6373 		win_set_static_tooltip( "Too far away to merge stations!" );
6374 	}
6375 }
6376 
do_work(player_t * player,const koord3d & last_pos,const koord3d & pos)6377 const char *tool_merge_stop_t::do_work( player_t *player, const koord3d &last_pos, const koord3d &pos)
6378 {
6379 	halt_be_merged_from = haltestelle_t::get_halt(pos,player);
6380 	halt_be_merged_to = haltestelle_t::get_halt(last_pos,player);
6381 	sint64 workcost = 0;
6382 	uint32 distance = 0x7FFFFFFFu;
6383 
6384 	FOR(slist_tpl<haltestelle_t::tile_t>, const& i, halt_be_merged_from->get_tiles()) {
6385 		FOR(slist_tpl<haltestelle_t::tile_t>, const& j, halt_be_merged_to->get_tiles()) {
6386 			uint32 dist = koord_distance( i.grund->get_pos(), j.grund->get_pos() );
6387 			if(  dist < distance  ) {
6388 				distance = dist;
6389 				if(  distance <= 1  ) {
6390 					break;
6391 				}
6392 			}
6393 		}
6394 		if(  distance <= 1  ) {
6395 			break;
6396 		}
6397 	}
6398 
6399 	if(  distance  < welt->get_settings().allow_merge_distant_halt  ) {
6400 		distance = clamp(distance,2,33)-2;
6401 		workcost = welt->scale_with_month_length( (1<<distance) * welt->get_settings().cst_multiply_merge_halt );
6402 		win_set_static_tooltip( tooltip_with_price("Building costs estimates", workcost) );
6403 		if(  player != welt->get_public_player()  &&  !player->can_afford(workcost)  ) {
6404 			return NOTICE_INSUFFICIENT_FUNDS;
6405 		}
6406 	}
6407 	else {
6408 		return "Too far away to merge stations!";
6409 	}
6410 
6411 	// and now just do it ...
6412 	halt_be_merged_to->merge_halt(halt_be_merged_from);
6413 	player_t::book_construction_costs( player, workcost, halt_be_merged_to->get_basis_pos(), ignore_wt );
6414 
6415 	// nothing to do
6416 	return NULL;
6417 }
6418 
init(player_t *)6419 bool tool_show_trees_t::init( player_t * )
6420 {
6421 	env_t::hide_trees = !env_t::hide_trees;
6422 	baum_t::recalc_outline_color();
6423 	welt->set_dirty();
6424 	return false;
6425 }
6426 
6427 
6428 sint8 tool_show_underground_t::save_underground_level = -128;
6429 
init(player_t *)6430 bool tool_show_underground_t::init( player_t * )
6431 {
6432 	koord3d zpos = welt->get_zeiger()->get_pos();
6433 	// move zeiger (pointer) to invalid position -> unmark tiles
6434 	welt->get_zeiger()->change_pos( koord3d::invalid);
6435 
6436 	sint8 old_underground_level = grund_t::underground_level;
6437 
6438 	// map needs update?
6439 	bool ok = true;
6440 	// need an extra click?
6441 	bool needs_click = false;
6442 
6443 	// default default-param = U for backward compatibility
6444 	if (default_param == NULL) {
6445 		default_param = strdup("U");
6446 	}
6447 	// now check the default parameter
6448 	switch(default_param[0]) {
6449 		// toggle sliced view by toolbar - height taken from extra mouse click
6450 		case 'C':
6451 			if(grund_t::underground_mode==grund_t::ugm_level) {
6452 				grund_t::set_underground_mode( grund_t::ugm_none, 0);
6453 			}
6454 			else if(grund_t::underground_mode==grund_t::ugm_none) {
6455 				needs_click = true;
6456 				ok = false;
6457 			}
6458 			else {
6459 				ok = false;
6460 			}
6461 			break;
6462 		// decrease slice level
6463 		case 'D':
6464 			if(grund_t::underground_mode==grund_t::ugm_level) {
6465 				if(  grund_t::underground_level > welt->min_height  ) {
6466 					grund_t::underground_level --;
6467 				}
6468 			}
6469 			else {
6470 				ok = false;
6471 			}
6472 			break;
6473 		// increase slice level
6474 		case 'I':
6475 			if(grund_t::underground_mode==grund_t::ugm_level) {
6476 				if(  grund_t::underground_level < welt->max_height  ) {
6477 					grund_t::underground_level ++;
6478 				}
6479 			}
6480 			else {
6481 				ok = false;
6482 			}
6483 			break;
6484 
6485 		// toggle sliced view by keyboard - height taken from cursor
6486 		case 'K':
6487 			if(grund_t::underground_mode==grund_t::ugm_level) {
6488 				// switch to normal or full-underground
6489 				grund_t::set_underground_mode( grund_t::ugm_none, 0);
6490 			}
6491 			else if(grund_t::underground_mode==grund_t::ugm_none) {
6492 				grund_t::set_underground_mode( grund_t::ugm_level, zpos.z);
6493 			}
6494 			else {
6495 				ok = false;
6496 			}
6497 			break;
6498 
6499 		//  switch between full underground or normal/sliced view
6500 		case 'U':
6501 			if (grund_t::underground_mode==grund_t::ugm_all) {
6502 				// check if the old level is valid then switch back to sliced view
6503 				if (-128<save_underground_level && save_underground_level<127) {
6504 					grund_t::set_underground_mode(grund_t::ugm_level, save_underground_level);
6505 				}
6506 				else {
6507 					grund_t::set_underground_mode(grund_t::ugm_none, 0);
6508 				}
6509 			}
6510 			else {
6511 				grund_t::set_underground_mode( grund_t::ugm_all, 0);
6512 			}
6513 			break;
6514 
6515 		default:
6516 			ok = false;
6517 			dbg->error( "tool_show_underground_t::init()", "Unknown command string \"%s\"", default_param );
6518 
6519 	}
6520 
6521 	// move zeiger (pointer) back
6522 	welt->get_zeiger()->change_pos( zpos);
6523 
6524 	if (ok) {
6525 		save_underground_level = old_underground_level;
6526 
6527 		// renew toolbar
6528 		tool_t::update_toolbars();
6529 
6530 		// recalc all images on map
6531 		welt->update_underground();
6532 	}
6533 	return needs_click;
6534 }
6535 
work(player_t * player,koord3d pos)6536 const char *tool_show_underground_t::work( player_t *player, koord3d pos)
6537 {
6538 	koord3d zpos = welt->get_zeiger()->get_pos();
6539 	// move zeiger (pointer) to invalid position -> unmark tiles
6540 	welt->get_zeiger()->change_pos( koord3d::invalid);
6541 
6542 	save_underground_level = grund_t::underground_level;
6543 	grund_t::set_underground_mode( grund_t::ugm_level, pos.z);
6544 
6545 	// move zeiger (pointer) back
6546 	welt->get_zeiger()->change_pos( zpos);
6547 
6548 	// renew toolbar
6549 	tool_t::update_toolbars();
6550 
6551 	// recalc all images on map
6552 	welt->update_underground();
6553 
6554 	if(player == welt->get_active_player()) {
6555 		welt->set_tool( general_tool[TOOL_QUERY], player );
6556 	}
6557 
6558 	return NULL;
6559 }
6560 
6561 
get_tooltip(player_t const *) const6562 char const* tool_show_underground_t::get_tooltip(player_t const*) const
6563 {
6564 	// no default-param == U for backward compatibility
6565 	if(  default_param == NULL  ) {
6566 		return translator::translate("underground mode");
6567 	}
6568 	// now check the default parameter
6569 	switch(default_param[0]) {
6570 		// toggle sliced view by toolbar - height taken from extra mouse click
6571 		case 'C':
6572 			return translator::translate("sliced underground mode");
6573 		// decrease slice level
6574 		case 'D':
6575 			return translator::translate("decrease underground view level");
6576 		// increase slice level
6577 		case 'I':
6578 			return translator::translate("increase underground view level");
6579 		// toggle sliced view by keyboard - height taken from cursor
6580 		case 'K':
6581 			return translator::translate("sliced underground mode");
6582 		//  switch between full underground or normal/sliced view
6583 		case 'U':
6584 		default:
6585 			return translator::translate("underground mode");
6586 	}
6587 }
6588 
is_selected() const6589 bool tool_show_underground_t::is_selected() const
6590 {
6591 	// default default-param = U for backward compatibility
6592 	if(  default_param == NULL  ) {
6593 		return grund_t::underground_mode==grund_t::ugm_all;
6594 	}
6595 	// now check the default parameter
6596 	switch(default_param[0]) {
6597 		// toggle sliced view by toolbar - height taken from extra mouse click
6598 		case 'C':
6599 			return grund_t::underground_mode==grund_t::ugm_level;
6600 		// decrease slice level
6601 		case 'D':
6602 			return false;
6603 		// increase slice level
6604 		case 'I':
6605 			return false;
6606 		// toggle sliced view by keyboard - height taken from cursor
6607 		case 'K':
6608 			return grund_t::underground_mode==grund_t::ugm_level;
6609 		//  switch between full underground or normal/sliced view
6610 		case 'U':
6611 			return grund_t::underground_mode==grund_t::ugm_all;
6612 	}
6613 	return false;
6614 }
6615 
draw_after(scr_coord k,bool dirty) const6616 void tool_show_underground_t::draw_after(scr_coord k, bool dirty) const
6617 {
6618 	if(  icon!=IMG_EMPTY  &&  is_selected()  ) {
6619 		display_img_blend( icon, k.x, k.y, TRANSPARENT50_FLAG|OUTLINE_FLAG|color_idx_to_rgb(COL_BLACK), false, dirty );
6620 		// additionally show level in sliced mode
6621 		if(  default_param!=NULL  &&  grund_t::underground_mode==grund_t::ugm_level  ) {
6622 			char level_str[16];
6623 			sprintf( level_str, "%i", grund_t::underground_level );
6624 			display_proportional_rgb( k.x+4, k.y+4, level_str, ALIGN_LEFT, color_idx_to_rgb(COL_YELLOW), true );
6625 		}
6626 	}
6627 }
6628 
6629 
draw_after(scr_coord pos,bool dirty) const6630 void tool_rotate90_t::draw_after(scr_coord pos, bool dirty) const
6631 {
6632 	if(  !env_t::networkmode  ) {
6633 		if(  skinverwaltung_t::compass_map  ) {
6634 			display_img_aligned( skinverwaltung_t::compass_map->get_image_id( welt->get_settings().get_rotation()+4 ), scr_rect(pos,env_t::iconsize), ALIGN_CENTER_V|ALIGN_CENTER_H, false );
6635 		}
6636 		tool_t::draw_after( pos, dirty );
6637 	}
6638 }
6639 
init(player_t *)6640 bool tool_rotate90_t::init( player_t * )
6641 {
6642 	if(  !env_t::networkmode  ) {
6643 		welt->rotate90();
6644 		welt->update_map();
6645 	}
6646 	return false;
6647 }
6648 
6649 
init(player_t *)6650 bool tool_quit_t::init( player_t * )
6651 {
6652 	destroy_all_win( true );
6653 	welt->stop( true );
6654 	return false;
6655 }
6656 
6657 
init(player_t *)6658 bool tool_screenshot_t::init( player_t * )
6659 {
6660 	if(  is_ctrl_pressed()  ) {
6661 		if(  const gui_frame_t * topwin = win_get_top()  ) {
6662 			const scr_coord k = win_get_pos(topwin);
6663 			const scr_size size = topwin->get_windowsize();
6664 			display_snapshot( k.x, k.y, size.w, size.h );
6665 		}
6666 		else {
6667 			display_snapshot( 0, 0, display_get_width(), display_get_height() );
6668 		}
6669 	}
6670 	else {
6671 		display_snapshot( 0, 0, display_get_width(), display_get_height() );
6672 	}
6673 	create_win( new news_img("Screenshot\ngespeichert.\n"), w_time_delete, magic_none);
6674 	return false;
6675 }
6676 
6677 
init(player_t * player)6678 bool tool_undo_t::init( player_t *player )
6679 {
6680 	if(!player->undo()  &&  can_use_gui()) {
6681 		create_win( new news_img("UNDO failed!"), w_time_delete, magic_none);
6682 	}
6683 	return false;
6684 }
6685 
6686 
init(player_t *)6687 bool tool_increase_industry_t::init( player_t * )
6688 {
6689 	factory_builder_t::increase_industry_density( false );
6690 	return false;
6691 }
6692 
6693 
init(player_t *)6694 bool tool_zoom_in_t::init( player_t * )
6695 {
6696 	win_change_zoom_factor(true);
6697 	welt->set_dirty();
6698 	return false;
6699 }
6700 
6701 
init(player_t *)6702 bool tool_zoom_out_t::init( player_t * )
6703 {
6704 	win_change_zoom_factor(false);
6705 	welt->set_dirty();
6706 	return false;
6707 }
6708 
6709 /************************* internal tools, only need for networking ***************/
6710 
scenario_check_schedule(karte_t * welt,player_t * player,schedule_t * schedule,bool local)6711 static bool scenario_check_schedule(karte_t *welt, player_t *player, schedule_t *schedule, bool local)
6712 {
6713 	if (!is_scenario()) {
6714 		return true;
6715 	}
6716 	const char* err = welt->get_scenario()->is_schedule_allowed(player, schedule);
6717 	if (err) {
6718 		if (*err  &&  local) {
6719 			open_error_msg_win(err);
6720 		}
6721 		return false;
6722 	}
6723 	return true;
6724 }
6725 
6726 
scenario_check_convoy(karte_t * welt,player_t * player,convoihandle_t cnv,depot_t * depot,bool local)6727 bool scenario_check_convoy(karte_t *welt, player_t *player, convoihandle_t cnv, depot_t* depot, bool local)
6728 {
6729 	if (!is_scenario()) {
6730 		return true;
6731 	}
6732 	const char* err = welt->get_scenario()->is_convoy_allowed(player, cnv, depot);
6733 	if (err) {
6734 		if (*err  &&  local) {
6735 			open_error_msg_win(err);
6736 		}
6737 		return false;
6738 	}
6739 	return true;
6740 }
6741 
6742 
6743 
6744 /* Handles all action of convois in depots. Needs a default param:
6745  * [function],[convoi_id],addition stuff
6746  * following simple command exists:
6747  * 'x' : self destruct
6748  * 'f' : open the schedule window
6749  * 'g' : apply a schedule
6750  * 'n' : toggle 'no load'
6751  * 'w' : toggle withdraw
6752  * 's' : change state to [number] (and maybe set open schedule flag)
6753  * 'l' : apply new line [number]
6754  * 'd' : go to nearest depot
6755  */
init(player_t * player)6756 bool tool_change_convoi_t::init( player_t *player )
6757 {
6758 	char tool=0;
6759 	uint16 convoi_id = 0;
6760 
6761 	// skip the rest of the command
6762 	const char *p = default_param;
6763 	while(  *p  &&  *p<=' '  ) {
6764 		p++;
6765 	}
6766 	sscanf( p, "%c,%hi", &tool, &convoi_id );
6767 
6768 	// skip to the commands ...
6769 	for(  int z = 2;  *p  &&  z>0;  p++  ) {
6770 		if(  *p==','  ) {
6771 			z--;
6772 		}
6773 	}
6774 
6775 	convoihandle_t cnv;
6776 	cnv.set_id( convoi_id );
6777 	// double click on remove button will send two such commands
6778 	// the first will delete the convoi, the second should not trigger an assertion
6779 	// catch such commands here
6780 	if( !cnv.is_bound()) {
6781 #if DEBUG>=4
6782 		if (can_use_gui()) {
6783 			create_win( new news_img("Convoy already deleted!"), w_time_delete, magic_none);
6784 		}
6785 #endif
6786 		dbg->warning("tool_change_convoi_t::init", "no convoy with id=%d found", convoi_id);
6787 		return false;
6788 	}
6789 	// ownership check for network games
6790 	if (cnv.is_bound()  &&  env_t::networkmode  &&  !player_t::check_owner(cnv->get_owner(), player)) {
6791 		return false;
6792 	}
6793 
6794 	// first letter is now the actual command
6795 	switch(  tool  ) {
6796 		case 'x': // self destruction ...
6797 			if(cnv.is_bound()) {
6798 				if (cnv->get_state()==convoi_t::INITIAL) {
6799 					// delete cnv in depot
6800 					if (grund_t *gr = welt->lookup(cnv->get_pos())) {
6801 						if (depot_t *dep = gr->get_depot()) {
6802 							dep->disassemble_convoi(cnv, true);
6803 							return false;
6804 						}
6805 					}
6806 				}
6807 				cnv->self_destruct();
6808 			}
6809 			return false;
6810 
6811 		case 'f': // open schedule
6812 			{
6813 				// we open the window only when executed on the same client that triggered the tool
6814 				// but the all clients must call the function anyway
6815 				cnv->open_schedule_window( can_use_gui() );
6816 			}
6817 			break;
6818 
6819 		case 'g': // change schedule
6820 			{
6821 				schedule_t *schedule = cnv->create_schedule()->copy();
6822 				schedule->finish_editing();
6823 				if (schedule->sscanf_schedule( p )  &&  scenario_check_schedule(welt, player, schedule, can_use_gui())) {
6824 					cnv->set_schedule( schedule );
6825 				}
6826 				else {
6827 					// could not read schedule, do not assign
6828 					delete schedule;
6829 				}
6830 			}
6831 			break;
6832 
6833 		case 'l': // change line
6834 			{
6835 				// read out id and new current_stop index
6836 				uint16 id=0, current_stop=0;
6837 				int count=sscanf( p, "%hi,%hi", &id, &current_stop );
6838 				linehandle_t l;
6839 				l.set_id( id );
6840 				if(  l.is_bound()  ) {
6841 					// sanity check for right line-type (compare schedule types ..)
6842 					schedule_t *schedule = cnv->create_schedule();
6843 					if(  schedule  &&  l->get_schedule()  &&  schedule->get_type()!=l->get_schedule()->get_type()  ) {
6844 						dbg->warning("tool_change_convoi_t::init", "types of convoi and line do not match");
6845 						return false;
6846 					}
6847 					if(  count==1 ) {
6848 						// current_stop was not supplied -> take it from line schedule
6849 						current_stop = l->get_schedule()->get_current_stop();
6850 					}
6851 					cnv->set_line( l );
6852 					cnv->get_schedule()->set_current_stop((uint8)current_stop);
6853 					cnv->get_schedule()->finish_editing();
6854 				}
6855 			}
6856 			break;
6857 
6858 		case 'n': // change no_load
6859 			cnv->set_no_load( !cnv->get_no_load() );
6860 			if(  !cnv->get_no_load()  ) {
6861 				cnv->set_withdraw( false );
6862 			}
6863 			break;
6864 
6865 		case 's': // change state
6866 			{
6867 				int new_state = atoi(p);
6868 				if(  new_state>0  ) {
6869 					cnv->set_state( new_state );
6870 					if(  new_state==convoi_t::EDIT_SCHEDULE  ) {
6871 						cnv->get_schedule()->start_editing();
6872 					}
6873 				}
6874 			}
6875 			break;
6876 
6877 		case 'w': // change withdraw
6878 			cnv->set_withdraw( !cnv->get_withdraw() );
6879 			cnv->set_no_load( cnv->get_withdraw() );
6880 			break;
6881 
6882 		case 'd': // goto depot
6883 		{
6884 			const char* msg = cnv->send_to_depot(is_local_execution());
6885 
6886 			if (is_local_execution()) {
6887 				create_win( new news_img(msg), w_time_delete, magic_none);
6888 			}
6889 		}
6890 	}
6891 
6892 	if(  cnv->in_depot()  &&  (tool=='g'  ||  tool=='l')  ) {
6893 		const grund_t *const ground = welt->lookup( cnv->get_home_depot() );
6894 		if(  ground  ) {
6895 			const depot_t *const depot = ground->get_depot();
6896 			if(  depot  ) {
6897 				depot_frame_t *const frame = dynamic_cast<depot_frame_t *>( win_get_magic( (ptrdiff_t)depot ) );
6898 				if(  frame  ) {
6899 					frame->update_data();
6900 				}
6901 			}
6902 		}
6903 	}
6904 
6905 
6906 	return false;	// no related work tool ...
6907 }
6908 
6909 
6910 
6911 /* Handles all action of lines. Needs a default param:
6912  * [function],[line_id],addition stuff
6913  * following simple command exists:
6914  * 'g' : apply new schedule to line [schedule follows]
6915  */
init(player_t * player)6916 bool tool_change_line_t::init( player_t *player )
6917 {
6918 	uint16 line_id = 0;
6919 
6920 	// skip the rest of the command
6921 	const char *p = default_param;
6922 	while(  *p  &&  *p<=' '  ) {
6923 		p++;
6924 	}
6925 
6926 	char tool=*p++;
6927 	while(  *p  &&  *p++!=','  ) {
6928 	}
6929 	if(  *p==0  ) {
6930 		dbg->warning( "tool_change_line_t::init()", "too short command \"%s\"", default_param );
6931 		return false;
6932 	}
6933 
6934 	line_id = atoi(p);
6935 	while(  *p  &&  *p++!=','  ) {
6936 	}
6937 
6938 	linehandle_t line;
6939 	line.set_id( line_id );
6940 
6941 	// ownership check for network games
6942 	if (line.is_bound()  &&  env_t::networkmode  && !player_t::check_owner(line->get_owner(), player)) {
6943 		return false;
6944 	}
6945 
6946 	// first letter is now the actual command
6947 	switch(  tool  ) {
6948 		case 'c': // create line, next parameter line type and magic of schedule window (only right window gets updated)
6949 			{
6950 				line = player->simlinemgmt.create_line( atoi(p), player );
6951 				while(  *p  &&  *p++!=','  ) {
6952 				}
6953 				long t;
6954 				sscanf( p, "%ld", &t );
6955 				while(  *p  &&  *p++!=','  ) {
6956 				}
6957 
6958 				line->get_schedule()->sscanf_schedule( p );
6959 				// check scenario conditions
6960 				if (!scenario_check_schedule(welt, player, line->get_schedule(), can_use_gui())) {
6961 					player->simlinemgmt.delete_line(line);
6962 					break;
6963 				}
6964 
6965 				line->get_schedule()->finish_editing();	// just in case ...
6966 				if(  can_use_gui()  ) {
6967 					schedule_gui_t *fg = dynamic_cast<schedule_gui_t *>(win_get_magic((ptrdiff_t)t));
6968 					if(  fg  ) {
6969 						fg->init_line_selector();
6970 					}
6971 					schedule_list_gui_t *sl = dynamic_cast<schedule_list_gui_t *>(win_get_magic(magic_line_management_t+player->get_player_nr()));
6972 					if(  sl  ) {
6973 						sl->show_lineinfo( line );
6974 					}
6975 					// no schedule window open => then open one
6976 					if(  fg==NULL  ) {
6977 						create_win( new line_management_gui_t(line, player), w_info, (ptrdiff_t)line.get_rep() );
6978 					}
6979 				}
6980 			}
6981 			break;
6982 
6983 		case 'd':	// delete line
6984 			{
6985 				if (line.is_bound()  &&  line->count_convoys()==0) {
6986 					// close a schedule window, if still active
6987 					gui_frame_t *w = win_get_magic( (ptrdiff_t)line.get_rep() );
6988 					if(w) {
6989 						destroy_win( w );
6990 					}
6991 					player->simlinemgmt.delete_line(line);
6992 				}
6993 			}
6994 			break;
6995 
6996 		case 'g': // change schedule
6997 			{
6998 				if (line.is_bound()) {
6999 					schedule_t *schedule = line->get_schedule()->copy();
7000 					if (schedule->sscanf_schedule( p )  &&  scenario_check_schedule(welt, player, schedule, can_use_gui()) ) {
7001 						schedule->finish_editing();
7002 						line->set_schedule( schedule );
7003 						line->get_owner()->simlinemgmt.update_line(line);
7004 					}
7005 					else {
7006 						// could not read schedule, do not assign
7007 						delete schedule;
7008 					}
7009 				}
7010 			}
7011 			break;
7012 
7013 		case 't':	// trims away convois on all lines of linetype with this default parameter
7014 			{
7015 				vector_tpl<linehandle_t> const& lines = player->simlinemgmt.get_line_list();
7016 				// what kind of lines to trim
7017 				const simline_t::linetype linetype = (simline_t::linetype)atoi(p);
7018 				while(  *p  &&  *p++!=','  ) {
7019 				}
7020 				// how much as target
7021 				sint32 percentage = *p ? atoi(p) : 10;
7022 				if(  percentage == 0  ) {
7023 					break;
7024 				}
7025 
7026 				FOR(vector_tpl<linehandle_t>,line,lines) {
7027 					if(  line->get_linetype() == linetype  &&  line->get_convoys().get_count() > 2  ) {
7028 						// correct waytpe and more than one,n now some up usage for the last six months
7029 						sint64 transported = 0, capacity = 0;
7030 						for(  int i=0;  i<6;  i++  ) {
7031 							capacity += line->get_finance_history( i , LINE_CAPACITY );
7032 							transported += line->get_finance_history( i , LINE_TRANSPORTED_GOODS );
7033 						}
7034 						// sanity check for non-moving lines
7035 						if(  capacity == 0  ) {
7036 							continue;
7037 						}
7038 
7039 						if(  (transported*100) / capacity < percentage  ) {
7040 							// less than 33 % usage => remove concois
7041 							vector_tpl<convoihandle_t> const& cnvs = line->get_convoys();
7042 							sint64 old_sum_capacity = 0;
7043 							FOR(vector_tpl<convoihandle_t>,cnv,cnvs) {
7044 								for(  int i=0;  i<cnv->get_vehicle_count();  i++  ) {
7045 									old_sum_capacity += cnv->get_vehikel(i)->get_desc()->get_capacity();
7046 								}
7047 							}
7048 							/* now we have the total capacity. We will now remove convois until this capacity
7049 							 * is reduced by the ration suggested from transported = 1/3 of total capacity
7050 							 * x is the percentage of used capacity
7051 							 * Then is the new target sum_capacity = x*old_sum_capacity
7052 							 */
7053 							sint64 new_sum_capacity = (transported * 1000 * old_sum_capacity) / (capacity * percentage * 10);
7054 
7055 							// first we remove the totally empty convois (nowbody will miss them)
7056 							int destroyed = 0;
7057 							const int initial = line->get_convoys().get_count();
7058 							const int max_left = (initial+2) / 2;
7059 
7060 							for(  int j=initial-1;  j >= 0  &&  initial-destroyed > max_left  &&  new_sum_capacity < old_sum_capacity;  j--  ) {
7061 								convoihandle_t cnv = line->get_convoy(j);
7062 								if(  cnv->get_state() == convoi_t::INITIAL  ||  cnv->get_state() >= convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH  ) {
7063 									for(  int i=0;  i<cnv->get_vehicle_count();  i++  ) {
7064 										old_sum_capacity -= cnv->get_vehikel(i)->get_desc()->get_capacity();
7065 									}
7066 									cnv->self_destruct();
7067 									destroyed ++;
7068 								}
7069 							}
7070 
7071 							// not enough? Then remove from the end ...
7072 							for(  uint j=0;  j < line->get_convoys().get_count()  &&  initial-destroyed > max_left  &&  new_sum_capacity < old_sum_capacity;  j++  ) {
7073 								convoihandle_t cnv = line->get_convoy(j);
7074 								if(  cnv->get_state() != convoi_t::SELF_DESTRUCT  ) {
7075 									for(  int i=0;  i<cnv->get_vehicle_count();  i++  ) {
7076 										old_sum_capacity -= cnv->get_vehikel(i)->get_desc()->get_capacity();
7077 									}
7078 									cnv->self_destruct();
7079 									destroyed ++;
7080 								}
7081 							}
7082 							// done
7083 							if(  destroyed  ) {
7084 								dbg->message( "tool_change_line_t::init", "trim line %s: Reduced from %d to %d convois", line->get_name(), initial, initial-destroyed );
7085 							}
7086 						}
7087 					}
7088 				}
7089 			}
7090 			break;
7091 
7092 		case 'u':	// unite all lineless convois with similar schedules
7093 			{
7094 				array_tpl<vector_tpl<convoihandle_t> > cnvs(welt->convoys().get_count());
7095 				uint32 max_cnvs=0;
7096 				FOR(vector_tpl<convoihandle_t>, cnv, welt->convoys()) {
7097 					// only check lineless convoys
7098 					if(  !cnv->get_line().is_bound()  ) {
7099 						bool found = false;
7100 						// check, if already matches existing convois schedule
7101 						for(  uint32 i=0;  i<max_cnvs  &&  !found;  i++  ) {
7102 							FOR(vector_tpl<convoihandle_t>, cnvcomp, cnvs[i] ) {
7103 								if(  cnvcomp->get_schedule()->matches( welt, cnv->get_schedule() )  ) {
7104 									found = true;
7105 									cnvs[i].append( cnv );
7106 									break;
7107 								}
7108 							}
7109 						}
7110 						// not added: then may be new line for this?
7111 						if(  !found  ) {
7112 							cnvs[max_cnvs++].append( cnv );
7113 						}
7114 					}
7115 				}
7116 				// now we have an array of one or more lineless convois
7117 				for(  uint32 i=0;  i<max_cnvs;  i++  ) {
7118 					// if there is more than one convois => new line
7119 					if(  cnvs[i].get_count()>1  ) {
7120 						line = player->simlinemgmt.create_line( cnvs[i][0]->get_schedule()->get_type(), player, cnvs[i][0]->get_schedule() );
7121 						FOR(vector_tpl<convoihandle_t>, cnv, cnvs[i] ) {
7122 							line->add_convoy( cnv );
7123 							cnv->set_line( line );
7124 						}
7125 					}
7126 				}
7127 			}
7128 			break;
7129 
7130 		case 'w': // change widthdraw
7131 			{
7132 				if (line.is_bound()) {
7133 					line->set_withdraw( atoi(p) );
7134 				}
7135 			}
7136 			break;
7137 	}
7138 	return false;
7139 }
7140 
7141 
7142 
7143 /* Handles all action of convois in depots. Needs a default param:
7144  * [function],[depot_pos_3d],[convoi_id],addition stuff
7145  * following simple command exists:
7146  * 'l' : creates a new line (convoi_id might be invalid) (+printf'd initial schedule)
7147  * 'b' : starts the convoi
7148  * 'B' : starts all convoys
7149  * 'c' : copies this convoi
7150  * 'd' : disassembles convoi
7151  * 's' : sells convoi
7152  * 'a' : appends a vehicle (+vehikel_name) uses the oldest
7153  * 'i' : inserts a vehicle in front (+vehikel_name) uses the oldest
7154  * 's' : sells a vehikel (+vehikel_name) uses the newest
7155  * 'r' : removes a vehikel (+number in convoi)
7156  * 'R' : removes all vehikels including (+number in convoi) to end
7157  */
init(player_t * player)7158 bool tool_change_depot_t::init( player_t *player )
7159 {
7160 	char tool=0;
7161 	koord pos2d;
7162 	sint16 z;
7163 	uint16 convoi_id;
7164 
7165 	// skip the rest of the command
7166 	const char *p = default_param;
7167 	while(  *p  &&  *p<=' '  ) {
7168 		p++;
7169 	}
7170 	sscanf( p, "%c,%hi,%hi,%hi,%hi", &tool, &pos2d.x, &pos2d.y, &z, &convoi_id );
7171 
7172 	koord3d pos(pos2d, z);
7173 
7174 	// skip to the commands ...
7175 	z = 5;
7176 	while(  *p  &&  z>0  ) {
7177 		if(  *p==','  ) {
7178 			z--;
7179 		}
7180 		p++;
7181 	}
7182 
7183 	grund_t *gr = welt->lookup(pos);
7184 	depot_t *depot = gr ? gr->get_depot() : NULL;
7185 	if(  depot==NULL  ){
7186 		dbg->warning("tool_change_depot_t::init", "no depot found at (%s)", pos.get_str());
7187 		return false;
7188 	}
7189 	if(  !player_t::check_owner( depot->get_owner(), player)  ) {
7190 		dbg->warning("tool_change_depot_t::init", "depot at (%s) belongs to another player", pos.get_str());
7191 		return false;
7192 	}
7193 
7194 	convoihandle_t cnv;
7195 	cnv.set_id( convoi_id );
7196 
7197 	// ok now do our stuff
7198 	switch(  tool  ) {
7199 		case 'l': { // create line schedule window
7200 			linehandle_t selected_line = depot->get_owner()->simlinemgmt.create_line(depot->get_line_type(),depot->get_owner());
7201 			// no need to check schedule for scenario conditions, as schedule is only copied
7202 			selected_line->get_schedule()->sscanf_schedule( p );
7203 
7204 			depot_frame_t *depot_frame = dynamic_cast<depot_frame_t *>(win_get_magic( (ptrdiff_t)depot ));
7205 			if(  can_use_gui()  ) {
7206 				if(  welt->get_active_player()==player  &&  depot_frame  ) {
7207 					create_win( new line_management_gui_t( selected_line, depot->get_owner() ), w_info, (ptrdiff_t)selected_line.get_rep() );
7208 				}
7209 			}
7210 
7211 			if(  depot_frame  ) {
7212 				if(  can_use_gui()  ) {
7213 					depot_frame->set_selected_line( selected_line );
7214 					depot_frame->apply_line();
7215 				}
7216 				depot_frame->update_data();
7217 			}
7218 
7219 			schedule_list_gui_t *sl = dynamic_cast<schedule_list_gui_t *>(win_get_magic( magic_line_management_t + player->get_player_nr() ));
7220 			if(  sl  ) {
7221 				sl->update_data( selected_line );
7222 			}
7223 			DBG_MESSAGE("depot_frame_t::new_line()","id=%d",selected_line.get_id() );
7224 			break;
7225 		}
7226 		case 'b': { // start a convoi from the depot
7227 			if(  cnv.is_bound()  ) {
7228 				depot->start_convoi(cnv, can_use_gui());
7229 			}
7230 			break;
7231 		}
7232 		case 'B': { // start all convoys
7233 			depot->start_all_convoys();
7234 			break;
7235 		}
7236 		case 'd':   // disassemble convoi
7237 		case 'v': { // sell convoi
7238 			depot->disassemble_convoi( cnv, tool=='v' );
7239 			break;
7240 		}
7241 		case 'c': { // copy this convoi
7242 			if(  cnv.is_bound()  ) {
7243 				if(  convoihandle_t::is_exhausted()  ) {
7244 					if(  can_use_gui()  ) {
7245 						create_win( new news_img("Convoi handles exhausted!"), w_time_delete, magic_none );
7246 					}
7247 					return false;
7248 				}
7249 				depot->copy_convoi( cnv, can_use_gui() );
7250 			}
7251 			break;
7252 		}
7253 		case 'a':   // append a vehicle
7254 		case 'i':   // insert a vehicle in front
7255 		case 's':   // sells a vehicle
7256 		case 'r':   // removes a vehicle (assumes a valid depot)
7257 		case 'R': { // removes all vehicles to end (assumes a valid depot)
7258 			if(  tool=='r'  ||  tool=='R'  ) {
7259 				// test may fail after double-click on the button:
7260 				// two remove cmds are sent, only the first will remove, the second should not trigger assertion failure
7261 				if ( cnv.is_bound() ) {
7262 					int start_nr = atoi(p);
7263 					int nr = start_nr;
7264 
7265 					// find end
7266 					while(nr<cnv->get_vehicle_count()) {
7267 						const vehicle_desc_t *info = cnv->get_vehikel(nr)->get_desc();
7268 						nr ++;
7269 						if(info->get_trailer_count()!=1) {
7270 							break;
7271 						}
7272 					}
7273 					// now remove the vehicles
7274 					if(  cnv->get_vehicle_count()==nr-start_nr  ||  (tool=='R'  &&  start_nr==0)  ) {
7275 						depot->disassemble_convoi(cnv, false);
7276 					}
7277 					else if(  tool=='R'  ) {
7278 						depot->remove_vehicles_to_end( cnv, start_nr );
7279 					}
7280 					else {
7281 						for(  int i=start_nr;  i<nr;  i++  ) {
7282 							depot->remove_vehicle(cnv, start_nr);
7283 						}
7284 					}
7285 				}
7286 			}
7287 			else {
7288 				// create and append it
7289 				const vehicle_desc_t *info = vehicle_builder_t::get_info( p );
7290 				// we have a valid vehicle there => now check for details
7291 				if(  info  ) {
7292 					// we buy/sell all vehicles together!
7293 					slist_tpl<const vehicle_desc_t *>new_vehicle_info;
7294 					const vehicle_desc_t *start_info = info;
7295 
7296 					if(tool!='a') {
7297 						// start of composition
7298 						while(  info->get_leader_count() == 1  &&  info->get_leader(0) != NULL  &&  !new_vehicle_info.is_contained(info)  ) {
7299 							info = info->get_leader(0);
7300 							new_vehicle_info.insert(info);
7301 						}
7302 						info = start_info;
7303 					}
7304 					while(info) {
7305 						new_vehicle_info.append( info );
7306 						if(info->get_trailer_count() != 1  ||  (tool == 'i'  &&  info == start_info)  ||  new_vehicle_info.is_contained(info->get_trailer(0))  ) {
7307 							break;
7308 						}
7309 						info = info->get_trailer(0);
7310 					}
7311 					// now we have a valid composition together
7312 					if(  tool=='s'  ) {
7313 						while(  new_vehicle_info.get_count()  ) {
7314 							// We sell the newest vehicle - gives most money back.
7315 							vehicle_t* veh = depot->find_oldest_newest(new_vehicle_info.remove_first(), false);
7316 							if(veh != NULL) {
7317 								depot->sell_vehicle(veh);
7318 							}
7319 						}
7320 					}
7321 					else {
7322 						// now check if we are allowed to buy this (we test only leading vehicle, so one can still buy hidden stuff)
7323 						info = new_vehicle_info.front();
7324 						if(  !info->is_available(welt->get_timeline_year_month())  &&  !welt->get_settings().get_allow_buying_obsolete_vehicles()  ) {
7325 							// only allow append/insert, if in depot do not create new obsolete vehicles
7326 							if(  !depot->find_oldest_newest(info, true)  ) {
7327 								// just fail silent
7328 								return false;
7329 							}
7330 						}
7331 
7332 						// append/insert into convoi; create one if needed
7333 						depot->clear_command_pending();
7334 						if(  !cnv.is_bound()  ) {
7335 							if(  convoihandle_t::is_exhausted()  ) {
7336 								if(  can_use_gui()  ) {
7337 									create_win( new news_img("Convoi handles exhausted!"), w_time_delete, magic_none);
7338 								}
7339 								return false;
7340 							}
7341 							// create a new convoi
7342 							cnv = depot->add_convoi( can_use_gui() );
7343 							cnv->set_name( new_vehicle_info.front()->get_name() );
7344 						}
7345 
7346 						// now we have a valid cnv
7347 						if(  cnv->get_vehicle_count()+new_vehicle_info.get_count() <= depot->get_max_convoi_length()  ) {
7348 
7349 							for(  unsigned i=0;  i<new_vehicle_info.get_count();  i++  ) {
7350 								// insert/append needs reverse order
7351 								unsigned nr = (tool=='i') ? new_vehicle_info.get_count()-i-1 : i;
7352 								// We add the oldest vehicle - newer stay for selling
7353 								const vehicle_desc_t* vb = new_vehicle_info.at(nr);
7354 								vehicle_t* veh = depot->find_oldest_newest(vb, true);
7355 								if(  veh == NULL  ) {
7356 									// nothing there => we buy it
7357 									veh = depot->buy_vehicle(vb);
7358 								}
7359 								depot->append_vehicle( cnv, veh, tool=='i', can_use_gui() );
7360 							}
7361 						}
7362 					}
7363 				}
7364 			}
7365 			depot->update_win();
7366 			break;
7367 		}
7368 	}
7369 	return false;
7370 }
7371 
7372 
7373 /* Handles all player stuff default_param:
7374  * [function],[player_id],[state]
7375  * following command exists:
7376  * 'a' : activate/deactivate player (depends on state)
7377  * 'c' : change player color
7378  * '$' : change bank account
7379  */
init(player_t * player_in)7380 bool tool_change_player_t::init( player_t *player_in)
7381 {
7382 	if(  default_param==NULL  ) {
7383 		dbg->warning( "tool_change_player_t::init()", "nothing to do!" );
7384 		return false;
7385 	}
7386 
7387 	// skip the rest of the command
7388 	const char *p = default_param;
7389 	while(  *p  &&  *p<=' '  ) {
7390 		p++;
7391 	}
7392 
7393 	char tool = 0;
7394 	int id = 0;
7395 	if (sscanf( p, "%c,%i", &tool, &id ) < 2) {
7396 		return false; // invalid command
7397 	}
7398 
7399 	player_t *player = welt->get_player(id);
7400 
7401 	// ok now do our stuff
7402 	switch(  tool  ) {
7403 		case 'a': // activate/deactivate AI
7404 			if(  player  &&  player->get_ai_id()!=player_t::HUMAN  &&  (player_in==welt->get_public_player()  ||  !env_t::networkmode)  ) {
7405 				int state = 0;
7406 				if (sscanf( p, "%c,%i,%i", &tool, &id, &state ) == 3) {
7407 					player->set_active(state);
7408 					welt->get_settings().set_player_active(id, player->is_active());
7409 				}
7410 			}
7411 			break;
7412 		case 'c': // change player color
7413 			if(  player  &&  player==player_in  ) {
7414 				int c1, c2, dummy;
7415 				sscanf( p, "%c,%i,%i,%i", &tool, &dummy, &c1, &c2 );
7416 				player->set_player_color( c1, c2 );
7417 			}
7418 			break;
7419 
7420 		case '$': // change bank account
7421 			if(  player  &&  player_in==welt->get_public_player() ) {
7422 				int delta;
7423 				if (sscanf(p, "%c,%i,%i", &tool, &id, &delta) == 3) {
7424 					player->get_finance()->book_account(delta);
7425 				}
7426 			}
7427 			break;
7428 
7429 		case 'n': // WAS: new player with type state
7430 		case 'f': // WAS: activate/deactivate freeplay
7431 			dbg->error( "tool_change_player_t::init()", "deprecated command called" );
7432 			break;
7433 	}
7434 
7435 	// update the window
7436 	ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t);
7437 	if (playerwin) {
7438 		playerwin->update_data();
7439 	}
7440 
7441 	return false;
7442 }
7443 
7444 
7445 /* Sets traffic light phases via default_param:
7446  * [pos],[ns_flag],[ticks]
7447  */
init(player_t * player)7448 bool tool_change_traffic_light_t::init( player_t *player )
7449 {
7450 	koord pos2d;
7451 	sint16 z, ns, ticks;
7452 	if(  5!=sscanf( default_param, "%hi,%hi,%hi,%hi,%hi", &pos2d.x, &pos2d.y, &z, &ns, &ticks )  ) {
7453 		return false;
7454 	}
7455 	koord3d pos(pos2d, z);
7456 	if(  grund_t *gr = welt->lookup(pos)  ) {
7457 		if( roadsign_t *rs = gr->find<roadsign_t>()  ) {
7458 			if(  (  rs->get_desc()->is_traffic_light()  ||  rs->get_desc()->is_private_way()  )  &&  player_t::check_owner(rs->get_owner(),player)  ) {
7459 				if(  ns == 1  ) {
7460 					rs->set_ticks_ns( (uint8)ticks );
7461 				}
7462 				else if(  ns == 0  ) {
7463 					rs->set_ticks_ow( (uint8)ticks );
7464 				}
7465 				else if(  ns == 2  ) {
7466 					rs->set_ticks_offset( (uint8)ticks );
7467 				}
7468 				// update the window
7469 				if(  rs->get_desc()->is_traffic_light()  ) {
7470 					trafficlight_info_t* trafficlight_win = (trafficlight_info_t*)win_get_magic((ptrdiff_t)rs);
7471 					if (trafficlight_win) {
7472 						trafficlight_win->update_data();
7473 					}
7474 				}
7475 				else {
7476 					privatesign_info_t* trafficlight_win = (privatesign_info_t*)win_get_magic((ptrdiff_t)rs);
7477 					if (trafficlight_win) {
7478 						trafficlight_win->update_data();
7479 					}
7480 				}
7481 			}
7482 		}
7483 	}
7484 	return false;
7485 }
7486 
7487 
7488 /**
7489  * change city:
7490  * g[x],[y],[allow_city_growth]
7491  */
init(player_t * player)7492 bool tool_change_city_t::init( player_t *player )
7493 {
7494 	if (player != welt->get_public_player()) {
7495 		return false;
7496 	}
7497 	koord k;
7498 	sint16 allow_growth;
7499 	if(  3!=sscanf( default_param, "g%hi,%hi,%hi", &k.x, &k.y, &allow_growth )  ) {
7500 		return false;
7501 	}
7502 	grund_t *gr = welt->lookup_kartenboden(k);
7503 	if (gr) {
7504 		gebaeude_t *gb = gr->find<gebaeude_t>();
7505 		if (gb) {
7506 			stadt_t *st = gb->get_stadt();
7507 			if (st) {
7508 				st->set_citygrowth_yesno(allow_growth);
7509 				city_info_t *stinfo = dynamic_cast<city_info_t*>(win_get_magic((ptrdiff_t)st));
7510 				if (stinfo) {
7511 					stinfo->update_data();
7512 				}
7513 			}
7514 		}
7515 	}
7516 	return false;
7517 }
7518 
7519 
7520 
7521 /* Handles renaming of ingame entities. Needs a default param:
7522  * [object='c|h|l|m|t|p|f'][id|pos],[name]
7523  * c=convoi, h=halt, l=line,  m=marker, t=town, p=player, f=factory
7524  * in case of marker / factory, id is a pos3d string
7525  */
init(player_t * player)7526 bool tool_rename_t::init(player_t *player)
7527 {
7528 	uint16 id = 0;
7529 	koord3d pos = koord3d::invalid;
7530 
7531 	// skip the rest of the command
7532 	const char *p = default_param;
7533 	const char what = *p++;
7534 	switch(  what  ) {
7535 		case 'h':
7536 		case 'l':
7537 		case 'c':
7538 		case 't':
7539 		case 'p':
7540 			id = atoi(p);
7541 			while(  *p>0  &&  *p++!=','  ) {
7542 			}
7543 			break;
7544 		case 'm':
7545 		case 'f': {
7546 			koord pos2d;
7547 			if(  3!=sscanf( p, "%hi,%hi,%hi", &pos2d.x, &pos2d.y, &id )  ) {
7548 				dbg->error( "tool_rename_t::init", "no position given for marker/factory! (%s)", default_param );
7549 				return false;
7550 			}
7551 			while(  *p>0  &&  *p++!=','  ) {
7552 			}
7553 			while(  *p>0  &&  *p++!=','  ) {
7554 			}
7555 			while(  *p>0  &&  *p++!=','  ) {
7556 			}
7557 			pos = koord3d(pos2d, id);
7558 			id = 0;
7559 			break;
7560 		}
7561 		default:
7562 			dbg->error( "tool_rename_t::init", "illegal request! (%s)", default_param );
7563 			return false;
7564 	}
7565 
7566 	// now for action ...
7567 	switch(  what  ) {
7568 		case 'h':
7569 		{
7570 			halthandle_t halt;
7571 			halt.set_id( id );
7572 			if(  halt.is_bound()  &&  (!env_t::networkmode  ||  player_t::check_owner(halt->get_owner(), player))  ) {
7573 				halt->set_name( p );
7574 				return false;
7575 			}
7576 			break;
7577 		}
7578 
7579 		case 'l':
7580 		{
7581 			linehandle_t line;
7582 			line.set_id( id );
7583 			if(  line.is_bound()  &&  (!env_t::networkmode  ||  player_t::check_owner(line->get_owner(), player))  ) {
7584 				line->set_name( p );
7585 
7586 				schedule_list_gui_t *sl = dynamic_cast<schedule_list_gui_t *>(win_get_magic(magic_line_management_t+player->get_player_nr()));
7587 				if(  sl  ) {
7588 					sl->update_data( line );
7589 				}
7590 				return false;
7591 			}
7592 			break;
7593 		}
7594 
7595 		case 'c':
7596 		{
7597 			convoihandle_t cnv;
7598 			cnv.set_id( id );
7599 			if(  cnv.is_bound()  &&  (!env_t::networkmode  ||  player_t::check_owner(cnv->get_owner(), player))  ) {
7600 				//  set name without ID
7601 				cnv->set_name( p, false );
7602 				return false;
7603 			}
7604 			break;
7605 		}
7606 
7607 		case 't':
7608 		{
7609 			if(  player == welt->get_public_player()  &&   id<welt->get_cities().get_count()  ) {
7610 				welt->get_cities()[id]->set_name( p );
7611 				return false;
7612 			}
7613 			break;
7614 		}
7615 
7616 		case 'm':
7617 			if(  grund_t *gr = welt->lookup(pos)  ) {
7618 				label_t *label = gr->find<label_t>();
7619 				if (label  &&  (!env_t::networkmode  ||  player_t::check_owner(label->get_owner(), player))  ) {
7620 					gr->set_text(p);
7621 				}
7622 				return false;
7623 			}
7624 			break;
7625 
7626 		case 'p': {
7627 			player_t *other = welt->get_player((uint8)id);
7628 			if(  other  &&  other == player  ) {
7629 				other->set_name(p);
7630 				return false;
7631 			}
7632 			break;
7633 		}
7634 
7635 		case 'f':
7636 		{
7637 			if(  player == welt->get_public_player()) {
7638 				if(  grund_t *gr = welt->lookup(pos)  ) {
7639 					if(  gebaeude_t* gb = gr->find<gebaeude_t>()  ) {
7640 						if (  fabrik_t *fab = gb->get_fabrik()  ) {
7641 							fab->set_name(p);
7642 							return false;
7643 						}
7644 					}
7645 				}
7646 			}
7647 		}
7648 	}
7649 	// we are only getting here, if we could not process this request
7650 	dbg->warning( "tool_rename_t::init", "could not perform (%s)", default_param );
7651 	return false;
7652 }
7653 
7654 
7655 /*
7656  * Add a message to the message queue
7657  */
init(player_t * player)7658 bool tool_add_message_t::init(player_t *player)
7659 {
7660 	if (  *default_param  ) {
7661 		uint32 type = atoi(default_param);
7662 		const char* text = strchr(default_param, ',');
7663 		if ((type & ~message_t::local_flag) >= message_t::MAX_MESSAGE_TYPE  ||  text == NULL) {
7664 			return false;
7665 		}
7666 		welt->get_message()->add_message( text+1, koord::invalid, type,
7667 							    type & message_t::local_flag ? color_idx_to_rgb(COL_BLACK) : PLAYER_FLAG|player->get_player_nr(), IMG_EMPTY );
7668 	}
7669 	return false;
7670 }
7671