1 /*
2  * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic licence.
5  * (see licence.txt)
6  *
7  * Renovation in dec 2004 for other vehicles, timeline
8  * @author prissi
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <math.h>
14 
15 #include "../simconvoi.h"
16 #include "../simdebug.h"
17 #include "../simdepot.h"
18 #include "../simhalt.h"
19 #include "../simintr.h"
20 #include "../simline.h"
21 #include "../simmesg.h"
22 #include "../simsound.h"
23 #include "../simticker.h"
24 #include "../simtool.h"
25 #include "../gui/simwin.h"
26 #include "../simworld.h"
27 #include "../display/viewport.h"
28 
29 #include "../bauer/brueckenbauer.h"
30 #include "../bauer/hausbauer.h"
31 #include "../bauer/tunnelbauer.h"
32 
33 #include "../descriptor/tunnel_desc.h"
34 #include "../descriptor/way_desc.h"
35 
36 #include "../boden/grund.h"
37 
38 #include "../dataobj/settings.h"
39 #include "../dataobj/scenario.h"
40 #include "../dataobj/loadsave.h"
41 #include "../dataobj/translator.h"
42 #include "../dataobj/environment.h"
43 
44 #include "../obj/bruecke.h"
45 #include "../obj/gebaeude.h"
46 #include "../obj/leitung2.h"
47 #include "../obj/tunnel.h"
48 
49 #include "../gui/messagebox.h"
50 #include "../gui/player_frame_t.h"
51 
52 #include "../utils/cbuffer_t.h"
53 #include "../utils/simstring.h"
54 
55 #include "../vehicle/simvehicle.h"
56 
57 #include "simplay.h"
58 #include "finance.h"
59 
60 karte_ptr_t player_t::welt;
61 
62 #ifdef MULTI_THREAD
63 #include "../utils/simthread.h"
64 static pthread_mutex_t load_mutex = PTHREAD_MUTEX_INITIALIZER;
65 #endif
66 
player_t(uint8 nr)67 player_t::player_t(uint8 nr) :
68 	simlinemgmt()
69 {
70 	finance = new finance_t(this, welt);
71 	player_nr = nr;
72 	player_age = 0;
73 	active = false;		// Don't start as an AI player
74 	locked = false;			// allowed to change anything
75 	unlock_pending = false;
76 
77 	headquarter_pos = koord::invalid;
78 	headquarter_level = 0;
79 
80 
81 	welt->get_settings().set_player_color_to_default(this);
82 
83 	// we have different AI, try to find out our type:
84 	sprintf(player_name_buf,"player %i",player_nr-1);
85 }
86 
87 
~player_t()88 player_t::~player_t()
89 {
90 	while(  !messages.empty()  ) {
91 		delete messages.remove_first();
92 	}
93 	destroy_win(magic_finances_t + get_player_nr());
94 	delete finance;
95 	finance = NULL;
96 }
97 
98 
book_construction_costs(player_t * const player,const sint64 amount,const koord k,const waytype_t wt)99 void player_t::book_construction_costs(player_t * const player, const sint64 amount, const koord k, const waytype_t wt)
100 {
101 	if(player!=NULL) {
102 		player->finance->book_construction_costs(amount, wt);
103 		if(k != koord::invalid) {
104 			player->add_money_message(amount, k);
105 		}
106 	}
107 }
108 
109 
add_maintenance(sint64 change,waytype_t const wt)110 sint64 player_t::add_maintenance(sint64 change, waytype_t const wt)
111 {
112 	int tmp = 0;
113 #ifdef MULTI_THREAD
114 		pthread_mutex_lock( &load_mutex  );
115 #endif
116 	tmp = finance->book_maintenance(change, wt);
117 #ifdef MULTI_THREAD
118 		pthread_mutex_unlock( &load_mutex  );
119 #endif
120 	return tmp;
121 }
122 
123 
add_money_message(const sint64 amount,const koord pos)124 void player_t::add_money_message(const sint64 amount, const koord pos)
125 {
126 	if(amount != 0  &&  player_nr != 1) {
127 		if(  koord_distance(welt->get_viewport()->get_world_position(),pos)<2*(uint32)(display_get_width()/get_tile_raster_width())+3  ) {
128 			// only display, if near the screen ...
129 			add_message(amount, pos);
130 
131 			// and same for sound too ...
132 			if(  amount>=10000  &&  !welt->is_fast_forward()  ) {
133 				welt->play_sound_area_clipped(pos, SFX_CASH);
134 			}
135 		}
136 	}
137 }
138 
139 
book_new_vehicle(const sint64 amount,const koord k,const waytype_t wt)140 void player_t::book_new_vehicle(const sint64 amount, const koord k, const waytype_t wt)
141 {
142 	finance->book_new_vehicle(amount, wt);
143 	add_money_message(amount, k);
144 }
145 
146 
book_revenue(const sint64 amount,const koord k,const waytype_t wt,sint32 index)147 void player_t::book_revenue(const sint64 amount, const koord k, const waytype_t wt, sint32 index)
148 {
149 	finance->book_revenue(amount, wt, index);
150 	add_money_message(amount, k);
151 }
152 
153 
book_running_costs(const sint64 amount,const waytype_t wt)154 void player_t::book_running_costs(const sint64 amount, const waytype_t wt)
155 {
156 	finance->book_running_costs(amount, wt);
157 }
158 
159 
book_toll_paid(const sint64 amount,const waytype_t wt)160 void player_t::book_toll_paid(const sint64 amount, const waytype_t wt)
161 {
162 	finance->book_toll_paid(amount, wt);
163 }
164 
165 
book_toll_received(const sint64 amount,const waytype_t wt)166 void player_t::book_toll_received(const sint64 amount, const waytype_t wt)
167 {
168 	finance->book_toll_received(amount, wt);
169 }
170 
171 
book_transported(const sint64 amount,const waytype_t wt,int index)172 void player_t::book_transported(const sint64 amount, const waytype_t wt, int index)
173 {
174 	finance->book_transported(amount, wt, index);
175 }
176 
book_delivered(const sint64 amount,const waytype_t wt,int index)177 void player_t::book_delivered(const sint64 amount, const waytype_t wt, int index)
178 {
179 	finance->book_delivered(amount, wt, index);
180 }
181 
182 
get_name() const183 const char* player_t::get_name() const
184 {
185 	return translator::translate(player_name_buf);
186 }
187 
188 
set_name(const char * new_name)189 void player_t::set_name(const char *new_name)
190 {
191 	tstrncpy( player_name_buf, new_name, lengthof(player_name_buf) );
192 
193 	// update player window
194 	if (ki_kontroll_t *frame = dynamic_cast<ki_kontroll_t *>( win_get_magic(magic_ki_kontroll_t) ) ) {
195 		frame->update_data();
196 	}
197 }
198 
199 
income_message_t(sint64 betrag,koord p)200 player_t::income_message_t::income_message_t( sint64 betrag, koord p )
201 {
202 	money_to_string(str, betrag/100.0);
203 	alter = 127;
204 	pos = p;
205 	amount = betrag;
206 }
207 
208 
operator new(size_t)209 void *player_t::income_message_t::operator new(size_t /*s*/)
210 {
211 	return freelist_t::gimme_node(sizeof(player_t::income_message_t));
212 }
213 
214 
operator delete(void * p)215 void player_t::income_message_t::operator delete(void *p)
216 {
217 	freelist_t::putback_node(sizeof(player_t::income_message_t),p);
218 }
219 
220 
display_messages()221 void player_t::display_messages()
222 {
223 	const viewport_t *vp = welt->get_viewport();
224 
225 	FOR(slist_tpl<income_message_t*>, const m, messages) {
226 
227 		const scr_coord scr_pos = vp->get_screen_coord(koord3d(m->pos,welt->lookup_hgt(m->pos)),koord(0,m->alter >> 4));
228 
229 		display_shadow_proportional_rgb( scr_pos.x, scr_pos.y, PLAYER_FLAG|color_idx_to_rgb(player_color_1+3), color_idx_to_rgb(COL_BLACK), m->str, true);
230 		if(  m->pos.x < 3  ||  m->pos.y < 3  ) {
231 			// very close to border => renew background
232 			welt->set_background_dirty();
233 		}
234 	}
235 }
236 
237 
age_messages(uint32)238 void player_t::age_messages(uint32 /*delta_t*/)
239 {
240 	for(slist_tpl<income_message_t *>::iterator iter = messages.begin(); iter != messages.end(); ) {
241 		income_message_t *m = *iter;
242 		m->alter -= 5;
243 
244 		if(m->alter<-80) {
245 			iter = messages.erase(iter);
246 			delete m;
247 		}
248 		else {
249 			++iter;
250 		}
251 	}
252 }
253 
254 
add_message(sint64 betrag,koord k)255 void player_t::add_message(sint64 betrag, koord k)
256 {
257 	if(  !messages.empty()  &&  messages.back()->pos==k  &&  messages.back()->alter==127  ) {
258 		// last message exactly at same place, not aged
259 		messages.back()->amount += betrag;
260 		money_to_string(messages.back()->str, messages.back()->amount/100.0);
261 	}
262 	else {
263 		// otherwise new message
264 		income_message_t *m = new income_message_t(betrag,k);
265 		messages.append( m );
266 	}
267 }
268 
269 
set_player_color(uint8 col1,uint8 col2)270 void player_t::set_player_color(uint8 col1, uint8 col2)
271 {
272 	player_color_1 = col1;
273 	player_color_2 = col2;
274 	display_set_player_color_scheme( player_nr, col1, col2 );
275 }
276 
277 
step()278 void player_t::step()
279 {
280 }
281 
282 
new_month()283 bool player_t::new_month()
284 {
285 	// since the messages must remain on the screen longer ...
286 	static cbuffer_t buf;
287 
288 	finance->new_month();
289 
290 	// new month has started => recalculate vehicle value
291 	calc_assets();
292 
293 	finance->calc_finance_history();
294 
295 	simlinemgmt.new_month();
296 
297 	// Bankrupt ?
298 	if(  finance->get_account_balance() < 0  ) {
299 		finance->increase_account_overdrawn();
300 		if(  !welt->get_settings().is_freeplay()  &&  player_nr != 1  ) {
301 			if(  welt->get_active_player_nr()==player_nr  &&  !env_t::networkmode  ) {
302 				if(  finance->get_netwealth() < 0 ) {
303 					destroy_all_win(true);
304 					create_win( display_get_width()/2-128, 40, new news_img("Bankrott:\n\nDu bist bankrott.\n"), w_info, magic_none);
305 					ticker::add_msg( translator::translate("Bankrott:\n\nDu bist bankrott.\n"), koord::invalid, PLAYER_FLAG + player_color_1 + 1 );
306 					welt->stop(false);
307 				}
308 				else if(  finance->get_netwealth()*10 < welt->get_settings().get_starting_money(welt->get_current_month()/12)  ){
309 					// tell the player (problem!)
310 					welt->get_message()->add_message( translator::translate("Net wealth less than 10% of starting capital!"), koord::invalid, message_t::problems, player_nr, IMG_EMPTY );
311 				}
312 				else {
313 					// tell the player (just warning)
314 					buf.clear();
315 					buf.printf( translator::translate("On loan since %i month(s)"), finance->get_account_overdrawn() );
316 					welt->get_message()->add_message( buf, koord::invalid, message_t::ai, player_nr, IMG_EMPTY );
317 				}
318 			}
319 			// no assets => nothing to go bankrupt about again
320 			else if(  finance->get_maintenance(TT_ALL) != 0  ||  finance->has_convoi()  ) {
321 
322 				// for AI, we only declare bankrupt, if total assets are below zero
323 				if(  finance->get_netwealth() < 0  ) {
324 					return false;
325 				}
326 				// tell the current player (even during networkgames)
327 				if(  welt->get_active_player_nr()==player_nr  ) {
328 					if(  finance->get_netwealth()*10 < welt->get_settings().get_starting_money(welt->get_current_month()/12)  ){
329 						// net wealth nearly spent (problem!)
330 						welt->get_message()->add_message( translator::translate("Net wealth near zero"), koord::invalid, message_t::problems, player_nr, IMG_EMPTY );
331 					}
332 					else {
333 						// just minus in account (just tell)
334 						buf.clear();
335 						buf.printf( translator::translate("On loan since %i month(s)"), finance->get_account_overdrawn() );
336 						welt->get_message()->add_message( buf, koord::invalid, message_t::ai, player_nr, IMG_EMPTY );
337 					}
338 				}
339 			}
340 		}
341 	}
342 	else {
343 		finance->set_account_overdrawn( 0 );
344 	}
345 
346 	if(  env_t::networkmode  &&  player_nr>1  &&  !active  ) {
347 		// find out dummy companies (i.e. no vehicle running within x months)
348 		if(  welt->get_settings().get_remove_dummy_player_months()  &&  player_age >= welt->get_settings().get_remove_dummy_player_months()  )  {
349 			bool no_cnv = true;
350 			const uint16 months = min( MAX_PLAYER_HISTORY_MONTHS,  welt->get_settings().get_remove_dummy_player_months() );
351 			for(  uint16 m=0;  m<months  &&  no_cnv;  m++  ) {
352 				no_cnv &= finance->get_history_com_month(m, ATC_ALL_CONVOIS) ==0;
353 			}
354 			const uint16 years = max( MAX_PLAYER_HISTORY_YEARS,  (welt->get_settings().get_remove_dummy_player_months() - 1) / 12 );
355 			for(  uint16 y=0;  y<years  &&  no_cnv;  y++  ) {
356 				no_cnv &= finance->get_history_com_year(y, ATC_ALL_CONVOIS)==0;
357 			}
358 			// never run a convoi => dummy
359 			if(  no_cnv  ) {
360 				return false; // remove immediately
361 			}
362 		}
363 
364 		// find out abandoned companies (no activity within x months)
365 		if(  welt->get_settings().get_unprotect_abandoned_player_months()  &&  player_age >= welt->get_settings().get_unprotect_abandoned_player_months()  )  {
366 			bool abandoned = true;
367 			const uint16 months = min( MAX_PLAYER_HISTORY_MONTHS,  welt->get_settings().get_unprotect_abandoned_player_months() );
368 			for(  uint16 m = 0;  m < months  &&  abandoned;  m++  ) {
369 				abandoned &= finance->get_history_veh_month(TT_ALL, m, ATV_NEW_VEHICLE)==0  &&  finance->get_history_veh_month(TT_ALL, m, ATV_CONSTRUCTION_COST)==0;
370 			}
371 			const uint16 years = min( MAX_PLAYER_HISTORY_YEARS, (welt->get_settings().get_unprotect_abandoned_player_months() - 1) / 12);
372 			for(  uint16 y = 0;  y < years  &&  abandoned;  y++  ) {
373 				abandoned &= finance->get_history_veh_year(TT_ALL, y, ATV_NEW_VEHICLE)==0  &&  finance->get_history_veh_year(TT_ALL, y, ATV_CONSTRUCTION_COST)==0;
374 			}
375 			// never changed convoi, never built => abandoned
376 			if(  abandoned  ) {
377 				pwd_hash.clear();
378 				locked = false;
379 				unlock_pending = false;
380 			}
381 		}
382 	}
383 
384 	// subtract maintenance after bankruptcy check
385 	finance->book_account( -finance->get_maintenance_with_bits(TT_ALL) );
386 	// company gets older ...
387 	player_age ++;
388 
389 	return true; // still active
390 }
391 
392 
calc_assets()393 void player_t::calc_assets()
394 {
395 	sint64 assets[TT_MAX];
396 	for(int i=0; i < TT_MAX; ++i){
397 		assets[i] = 0;
398 	}
399 	// all convois
400 	FOR(vector_tpl<convoihandle_t>, const cnv, welt->convoys()) {
401 		if(  cnv->get_owner() == this  ) {
402 			sint64 restwert = cnv->calc_restwert();
403 			assets[TT_ALL] += restwert;
404 			assets[finance->translate_waytype_to_tt(cnv->front()->get_desc()->get_waytype())] += restwert;
405 		}
406 	}
407 
408 	// all vehikels stored in depot not part of a convoi
409 	FOR(slist_tpl<depot_t*>, const depot, depot_t::get_depot_list()) {
410 		if(  depot->get_player_nr() == player_nr  ) {
411 			FOR(slist_tpl<vehicle_t*>, const veh, depot->get_vehicle_list()) {
412 				sint64 restwert = veh->calc_sale_value();
413 				assets[TT_ALL] += restwert;
414 				assets[finance->translate_waytype_to_tt(veh->get_desc()->get_waytype())] += restwert;
415 			}
416 		}
417 	}
418 
419 	finance->set_assets(assets);
420 }
421 
422 
update_assets(sint64 const delta,const waytype_t wt)423 void player_t::update_assets(sint64 const delta, const waytype_t wt)
424 {
425 	finance->update_assets(delta, wt);
426 }
427 
428 
get_scenario_completion() const429 sint32 player_t::get_scenario_completion() const
430 {
431 	return finance->get_scenario_completed();
432 }
433 
434 
set_scenario_completion(sint32 percent)435 void player_t::set_scenario_completion(sint32 percent)
436 {
437 	finance->set_scenario_completed(percent);
438 }
439 
440 
check_owner(const player_t * owner,const player_t * test)441 bool player_t::check_owner( const player_t *owner, const player_t *test )
442 {
443 	return owner == test  ||  owner == NULL  ||  test == welt->get_public_player();
444 }
445 
446 
ai_bankrupt()447 void player_t::ai_bankrupt()
448 {
449 	player_t *const psplayer = welt->get_public_player();
450 
451 	DBG_MESSAGE("player_t::ai_bankrupt()","Removing convois");
452 
453 	for (size_t i = welt->convoys().get_count(); i-- != 0;) {
454 		convoihandle_t const cnv = welt->convoys()[i];
455 		if(cnv->get_owner()!=this) {
456 			continue;
457 		}
458 
459 		linehandle_t line = cnv->get_line();
460 
461 		cnv->self_destruct();
462 		// convois not in depots must step to really get rid of them
463 		if(  cnv.is_bound()  &&  cnv->get_state() != convoi_t::INITIAL  ) {
464 			cnv->step();
465 		}
466 
467 		// last vehicle on that connection (no line => railroad)
468 		if(  !line.is_bound()  ||  line->count_convoys()==0  ) {
469 			simlinemgmt.delete_line( line );
470 		}
471 	}
472 
473 	// remove headquarters pos
474 	headquarter_pos = koord::invalid;
475 
476 	// remove all stops
477 	// first generate list of our stops
478 	slist_tpl<halthandle_t> halt_list;
479 	FOR(vector_tpl<halthandle_t>, const halt, haltestelle_t::get_alle_haltestellen()) {
480 		if(  halt->get_owner()==this  ) {
481 			halt_list.append(halt);
482 		}
483 	}
484 	// ... and destroy them
485 	while (!halt_list.empty()) {
486 		halthandle_t h = halt_list.remove_first();
487 		haltestelle_t::destroy( h );
488 	}
489 
490 	// transfer all ways in public stops belonging to me to no one
491 	FOR(vector_tpl<halthandle_t>, const halt, haltestelle_t::get_alle_haltestellen()) {
492 		if(  halt->get_owner()==welt->get_public_player()  ) {
493 			// only concerns public stops tiles
494 			FOR(slist_tpl<haltestelle_t::tile_t>, const& i, halt->get_tiles()) {
495 				grund_t const* const gr = i.grund;
496 				for(  uint8 wnr=0;  wnr<2;  wnr++  ) {
497 					weg_t *w = gr->get_weg_nr(wnr);
498 					// make public
499 					if(  w  &&  w->get_owner()==this  ) {
500 						// tunnels and bridges are handled later? (logic needs to be checked for correct maintenance costs)
501 						if (!gr->ist_bruecke()  &&  !gr->ist_tunnel()) {
502 							sint32 const costs = w->get_desc()->get_maintenance();
503 							waytype_t const wt = w->get_desc()->get_finance_waytype();
504 							player_t::add_maintenance(this, -costs, wt);
505 							player_t::add_maintenance(psplayer, costs, wt);
506 						}
507 						w->set_owner(psplayer);
508 					}
509 				}
510 			}
511 		}
512 	}
513 
514 	// deactivate active tool (remove dummy grounds)
515 	welt->set_tool(tool_t::general_tool[TOOL_QUERY], this);
516 
517 	// next remove all ways, depot etc, that are not road or channels
518 	for( int y=0;  y<welt->get_size().y;  y++  ) {
519 		for( int x=0;  x<welt->get_size().x;  x++  ) {
520 			planquadrat_t *plan = welt->access(x,y);
521 			for (size_t b = plan->get_boden_count(); b-- != 0;) {
522 				grund_t *gr = plan->get_boden_bei(b);
523 				// remove tunnel and bridges first
524 				if(  gr->get_top()>0  &&  gr->obj_bei(0)->get_owner()==this   &&  (gr->ist_bruecke()  ||  gr->ist_tunnel())  ) {
525 					koord3d pos = gr->get_pos();
526 
527 					waytype_t wt = gr->hat_wege() ? gr->get_weg_nr(0)->get_waytype() : powerline_wt;
528 					if (gr->ist_bruecke()) {
529 						bridge_builder_t::remove( this, pos, wt );
530 						// fails if powerline bridge somehow connected to powerline bridge of another player
531 					}
532 					else {
533 						tunnel_builder_t::remove( this, pos, wt, true );
534 					}
535 					// maybe there are some objects left (station on bridge head etc)
536 					gr = plan->get_boden_in_hoehe(pos.z);
537 					if (gr == NULL) {
538 						continue;
539 					}
540 				}
541 				for (uint8 i = gr->get_top(); i-- != 0;) {
542 					obj_t *obj = gr->obj_bei(i);
543 					if(obj->get_owner()==this) {
544 						sint32 costs = 0;
545 						waytype_t wt = ignore_wt;
546 						switch(obj->get_typ()) {
547 							case obj_t::roadsign:
548 							case obj_t::signal:
549 							case obj_t::airdepot:
550 							case obj_t::bahndepot:
551 							case obj_t::monoraildepot:
552 							case obj_t::tramdepot:
553 							case obj_t::strassendepot:
554 							case obj_t::schiffdepot:
555 							case obj_t::senke:
556 							case obj_t::pumpe:
557 							case obj_t::wayobj:
558 							case obj_t::label:
559 								obj->cleanup(this);
560 								delete obj;
561 								break;
562 							case obj_t::leitung:
563 								// do not remove powerline from bridges
564 								if(gr->ist_bruecke()) {
565 									costs = ((leitung_t*)obj)->get_desc()->get_maintenance();
566 									add_maintenance(-costs, powerline_wt);
567 									psplayer->add_maintenance(costs, powerline_wt);
568 									obj->set_owner(psplayer);
569 								}
570 								else {
571 									obj->cleanup(this);
572 									delete obj;
573 								}
574 								break;
575 							case obj_t::gebaeude:
576 								hausbauer_t::remove( this, (gebaeude_t *)obj );
577 								break;
578 							case obj_t::way:
579 							{
580 								weg_t *w=(weg_t *)obj;
581 								// tunnels and bridges made public
582 								if (gr->ist_bruecke()  ||  gr->ist_tunnel()) {
583 									w->set_owner(psplayer);
584 								}
585 								// roads and water ways also made public
586 								else if(w->get_waytype()==road_wt  ||  w->get_waytype()==water_wt) {
587 									costs = w->get_desc()->get_maintenance();
588 									wt = w->get_waytype();
589 									add_maintenance(-costs, wt);
590 									psplayer->add_maintenance(costs, wt);
591 									w->set_owner(psplayer);
592 								}
593 								else {
594 									gr->weg_entfernen( w->get_waytype(), true );
595 								}
596 								break;
597 							}
598 							case obj_t::bruecke:
599 								costs = ((bruecke_t*)obj)->get_desc()->get_maintenance();
600 								wt = obj->get_waytype();
601 								add_maintenance(-costs, wt);
602 								psplayer->add_maintenance(costs, wt);
603 								obj->set_owner(psplayer);
604 								break;
605 							case obj_t::tunnel:
606 								costs = ((tunnel_t*)obj)->get_desc()->get_maintenance();
607 								wt = ((tunnel_t*)obj)->get_desc()->get_finance_waytype();
608 								add_maintenance(-costs, wt);
609 								psplayer->add_maintenance(costs, wt);
610 								obj->set_owner(psplayer);
611 								break;
612 
613 							default:
614 								obj->set_owner(psplayer);
615 						}
616 					}
617 				}
618 				// remove empty tiles (elevated ways)
619 				if (!gr->ist_karten_boden()  &&  gr->get_top()==0) {
620 					plan->boden_entfernen(gr);
621 				}
622 			}
623 		}
624 	}
625 
626 	active = false;
627 	// make account negative
628 	if (finance->get_account_balance() > 0) {
629 		finance->book_account( -finance->get_account_balance() -1 );
630 	}
631 
632 	cbuffer_t buf;
633 	buf.printf( translator::translate("%s\nwas liquidated."), get_name() );
634 	welt->get_message()->add_message( buf, koord::invalid, message_t::ai, PLAYER_FLAG|player_nr );
635 }
636 
637 
rdwr(loadsave_t * file)638 void player_t::rdwr(loadsave_t *file)
639 {
640 	xml_tag_t sss( file, "spieler_t" );
641 
642 	if(file->is_version_less(112, 5)) {
643 		sint64 konto = finance->get_account_balance();
644 		file->rdwr_longlong(konto);
645 		finance->set_account_balance(konto);
646 
647 		sint32 account_overdrawn = finance->get_account_overdrawn();
648 		file->rdwr_long(account_overdrawn);
649 		finance->set_account_overdrawn( account_overdrawn );
650 	}
651 
652 	if(file->is_version_less(101, 0)) {
653 		// ignore steps
654 		sint32 ldummy=0;
655 		file->rdwr_long(ldummy);
656 	}
657 
658 	if(file->is_version_less(99, 9)) {
659 		sint32 farbe;
660 		file->rdwr_long(farbe);
661 		player_color_1 = (uint8)farbe*2;
662 		player_color_2 = player_color_1+24;
663 	}
664 	else {
665 		file->rdwr_byte(player_color_1);
666 		file->rdwr_byte(player_color_2);
667 	}
668 
669 	sint32 halt_count=0;
670 	if(file->is_version_less(99, 8)) {
671 		file->rdwr_long(halt_count);
672 	}
673 	if(file->is_version_less(112, 3)) {
674 		sint32 haltcount = 0;
675 		file->rdwr_long(haltcount);
676 	}
677 
678 	// save all the financial statistics
679 	finance->rdwr( file );
680 
681 	file->rdwr_bool(active);
682 
683 	// state is not saved anymore
684 	if(file->is_version_less(99, 14)) {
685 		sint32 ldummy=0;
686 		file->rdwr_long(ldummy);
687 		file->rdwr_long(ldummy);
688 	}
689 
690 	// the AI stuff is now saved directly by the different AI
691 	if(  file->is_version_less(101, 0)) {
692 		sint32 ldummy = -1;
693 		file->rdwr_long(ldummy);
694 		file->rdwr_long(ldummy);
695 		file->rdwr_long(ldummy);
696 		file->rdwr_long(ldummy);
697 		koord k(-1,-1);
698 		k.rdwr( file );
699 		k.rdwr( file );
700 	}
701 
702 	if(file->is_loading()) {
703 
704 		// halt_count will be zero for newer savegames
705 DBG_DEBUG("player_t::rdwr()","player %i: loading %i halts.",welt->sp2num( this ),halt_count);
706 		for(int i=0; i<halt_count; i++) {
707 			haltestelle_t::create( file );
708 		}
709 		// empty undo buffer
710 		init_undo(road_wt,0);
711 	}
712 
713 	// headquarters stuff
714 	if (file->is_version_less(86, 4))
715 	{
716 		headquarter_level = 0;
717 		headquarter_pos = koord::invalid;
718 	}
719 	else {
720 		file->rdwr_long(headquarter_level);
721 		headquarter_pos.rdwr( file );
722 		if(file->is_loading()) {
723 			if(headquarter_level<0) {
724 				headquarter_pos = koord::invalid;
725 				headquarter_level = 0;
726 			}
727 		}
728 	}
729 
730 	// line management
731 	if(file->is_version_atleast(88, 3)) {
732 		simlinemgmt.rdwr(file,this);
733 	}
734 
735 	if(file->is_version_atleast(102, 3)) {
736 		// password hash
737 		for(  int i=0;  i<20;  i++  ) {
738 			file->rdwr_byte(pwd_hash[i]);
739 		}
740 		if(  file->is_loading()  ) {
741 			// disallow all actions, if password set (might be unlocked by password gui )
742 			locked = !pwd_hash.empty();
743 		}
744 	}
745 
746 	// save the name too
747 	if(  file->is_version_atleast(102, 4)  ) {
748 		file->rdwr_str( player_name_buf, lengthof(player_name_buf) );
749 	}
750 
751 	// save age
752 	if(  file->is_version_atleast(112, 2)  ) {
753 		file->rdwr_short( player_age );
754 	}
755 }
756 
757 
finish_rd()758 void player_t::finish_rd()
759 {
760 	simlinemgmt.finish_rd();
761 	display_set_player_color_scheme( player_nr, player_color_1, player_color_2 );
762 	// recalculate vehicle value
763 	calc_assets();
764 
765 	finance->calc_finance_history();
766 }
767 
768 
rotate90(const sint16 y_size)769 void player_t::rotate90( const sint16 y_size )
770 {
771 	simlinemgmt.rotate90( y_size );
772 	headquarter_pos.rotate90( y_size );
773 }
774 
775 
report_vehicle_problem(convoihandle_t cnv,const koord3d position)776 void player_t::report_vehicle_problem(convoihandle_t cnv,const koord3d position)
777 {
778 	switch(cnv->get_state()) {
779 
780 		case convoi_t::NO_ROUTE:
781 DBG_MESSAGE("player_t::report_vehicle_problem","Vehicle %s can't find a route to (%i,%i)!", cnv->get_name(),position.x,position.y);
782 			{
783 				cbuffer_t buf;
784 				buf.printf( translator::translate("Vehicle %s can't find a route!"), cnv->get_name());
785 				welt->get_message()->add_message( (const char *)buf, cnv->get_pos().get_2d(), message_t::problems, PLAYER_FLAG | player_nr, cnv->front()->get_base_image());
786 			}
787 			break;
788 
789 		case convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH:
790 		case convoi_t::CAN_START_ONE_MONTH:
791 		case convoi_t::CAN_START_TWO_MONTHS:
792 DBG_MESSAGE("player_t::report_vehicle_problem","Vehicle %s stuck!", cnv->get_name(),position.x,position.y);
793 			{
794 				cbuffer_t buf;
795 				buf.printf( translator::translate("Vehicle %s is stucked!"), cnv->get_name());
796 				welt->get_message()->add_message( (const char *)buf, cnv->get_pos().get_2d(), message_t::warnings, PLAYER_FLAG | player_nr, cnv->front()->get_base_image());
797 			}
798 			break;
799 
800 		default:
801 DBG_MESSAGE("player_t::report_vehicle_problem","Vehicle %s, state %i!", cnv->get_name(), cnv->get_state());
802 	}
803 	(void)position;
804 }
805 
806 
init_undo(waytype_t wtype,unsigned short max)807 void player_t::init_undo( waytype_t wtype, unsigned short max )
808 {
809 	// only human player
810 	// prissi: allow for UNDO for real player
811 DBG_MESSAGE("player_t::int_undo()","undo tiles %i",max);
812 	last_built.clear();
813 	last_built.resize(max+1);
814 	if(max>0) {
815 		undo_type = wtype;
816 	}
817 
818 }
819 
820 
add_undo(koord3d k)821 void player_t::add_undo(koord3d k)
822 {
823 	if(last_built.get_size()>0) {
824 //DBG_DEBUG("player_t::add_undo()","tile at (%i,%i)",k.x,k.y);
825 		last_built.append(k);
826 	}
827 }
828 
829 
undo()830 sint64 player_t::undo()
831 {
832 	if (last_built.empty()) {
833 		// nothing to UNDO
834 		return false;
835 	}
836 	// check, if we can still do undo
837 	FOR(vector_tpl<koord3d>, const& i, last_built) {
838 		grund_t* const gr = welt->lookup(i);
839 		if(gr==NULL  ||  gr->get_typ()!=grund_t::boden) {
840 			// well, something was built here ... so no undo
841 			last_built.clear();
842 			return false;
843 		}
844 		// we allow ways, unimportant stuff but no vehicles, signals, wayobjs etc
845 		if(gr->obj_count()>0) {
846 			for( unsigned i=0;  i<gr->get_top();  i++  ) {
847 				switch(gr->obj_bei(i)->get_typ()) {
848 					// these are allowed
849 					case obj_t::zeiger:
850 					case obj_t::wolke:
851 					case obj_t::leitung:
852 					case obj_t::pillar:
853 					case obj_t::way:
854 					case obj_t::label:
855 					case obj_t::crossing:
856 					case obj_t::pedestrian:
857 					case obj_t::road_user:
858 					case obj_t::movingobj:
859 						break;
860 					// special case airplane
861 					// they can be everywhere, so we allow for everything but runway undo
862 					case obj_t::air_vehicle: {
863 						if(undo_type!=air_wt) {
864 							break;
865 						}
866 						const air_vehicle_t* aircraft = obj_cast<air_vehicle_t>(gr->obj_bei(i));
867 						// flying aircrafts are ok
868 						if(!aircraft->is_on_ground()) {
869 							break;
870 						}
871 					}
872 					/* FALLTHROUGH */
873 					// all other are forbidden => no undo any more
874 					default:
875 						last_built.clear();
876 						return false;
877 				}
878 			}
879 		}
880 	}
881 
882 	// ok, now remove everything last built
883 	sint64 cost=0;
884 	FOR(vector_tpl<koord3d>, const& i, last_built) {
885 		grund_t* const gr = welt->lookup(i);
886 		if(  undo_type != powerline_wt  ) {
887 			cost += gr->weg_entfernen(undo_type,true);
888 		}
889 		else {
890 			if (leitung_t* lt = gr->get_leitung()) {
891 				cost += lt->get_desc()->get_price();
892 				lt->cleanup(NULL);
893 				delete lt;
894 			}
895 		}
896 	}
897 	last_built.clear();
898 	return cost;
899 }
900 
901 
tell_tool_result(tool_t * tool,koord3d,const char * err)902 void player_t::tell_tool_result(tool_t *tool, koord3d, const char *err)
903 {
904 	/* tools can return three kinds of messages
905 	 * NULL = success
906 	 * "" = failure, but just do not try again
907 	 * "bla" error message, which should be shown
908 	 */
909 	if (welt->get_active_player()==this) {
910 		if(err==NULL) {
911 			if(tool->ok_sound!=NO_SOUND) {
912 				sound_play(tool->ok_sound);
913 			}
914 		}
915 		else if(*err!=0) {
916 			// something went really wrong
917 			sound_play(SFX_FAILURE);
918 			// look for coordinate in error message
919 			// syntax: either @x,y or (x,y)
920 			open_error_msg_win(err);
921 		}
922 	}
923 }
924 
925 
book_convoi_number(int count)926 void player_t::book_convoi_number(int count)
927 {
928 	finance->book_convoi_number(count);
929 }
930 
931 
get_account_balance_as_double() const932 double player_t::get_account_balance_as_double() const
933 {
934 	return finance->get_account_balance() / 100.0;
935 }
936 
937 
get_account_overdrawn() const938 int player_t::get_account_overdrawn() const
939 {
940 	return finance->get_account_overdrawn();
941 }
942 
943 
has_money_or_assets() const944 bool player_t::has_money_or_assets() const
945 {
946 	return finance->has_money_or_assets();
947 }
948 
can_afford(sint64 cost) const949 bool player_t::can_afford(sint64 cost) const
950 {
951 	return welt->get_settings().is_freeplay() ||
952 		is_public_service() ||
953 		get_finance()->get_netwealth() >= -cost;
954 }
955 
is_public_service() const956 bool player_t::is_public_service() const
957 {
958 	return get_player_nr() == 1;
959 }
960