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 
8 #include <stdio.h>
9 
10 #include "../simworld.h"
11 #include "../simobj.h"
12 #include "../player/simplay.h"
13 #include "../boden/grund.h"
14 #include "../display/simimg.h"
15 #include "../bauer/tunnelbauer.h"
16 
17 #include "../dataobj/loadsave.h"
18 #include "../dataobj/translator.h"
19 
20 #include "../descriptor/tunnel_desc.h"
21 
22 #include "leitung2.h"
23 #include "../bauer/wegbauer.h"
24 
25 #include "tunnel.h"
26 
27 #ifdef MULTI_THREAD
28 #include "../utils/simthread.h"
29 static pthread_mutex_t tunnel_calc_image_mutex;
30 static recursive_mutex_maker_t tunnel_cim_maker(tunnel_calc_image_mutex);
31 #endif
32 
33 
tunnel_t(loadsave_t * const file)34 tunnel_t::tunnel_t(loadsave_t* const file) : obj_no_info_t()
35 {
36 	desc = 0;
37 	rdwr(file);
38 	image = foreground_image = IMG_EMPTY;
39 	broad_type = 0;
40 }
41 
42 
tunnel_t(koord3d pos,player_t * player,const tunnel_desc_t * desc)43 tunnel_t::tunnel_t(koord3d pos, player_t *player, const tunnel_desc_t *desc) :
44 	obj_no_info_t(pos)
45 {
46 	assert(desc);
47 	this->desc = desc;
48 	set_owner( player );
49 	image = foreground_image = IMG_EMPTY;
50 	broad_type = 0;
51 }
52 
53 
get_waytype() const54 waytype_t tunnel_t::get_waytype() const
55 {
56 	return desc ? desc->get_waytype() : invalid_wt;
57 }
58 
59 
calc_image()60 void tunnel_t::calc_image()
61 {
62 #ifdef MULTI_THREAD
63 	pthread_mutex_lock( &tunnel_calc_image_mutex );
64 #endif
65 	const grund_t *gr = welt->lookup(get_pos());
66 	if(  gr->ist_karten_boden()  &&  desc  ) {
67 		slope_t::type hang = gr->get_grund_hang();
68 
69 		broad_type = 0;
70 		if(  desc->has_broad_portals()  ) {
71 			ribi_t::ribi dir = ribi_t::rotate90( ribi_type( hang ) );
72 			if(  dir==0  ) {
73 				dbg->error( "tunnel_t::calc_image()", "pos=%s, dir=%i, hang=%i", get_pos().get_str(), dir, hang );
74 			}
75 			else {
76 				const grund_t *gr_l = welt->lookup(get_pos() + dir);
77 				tunnel_t* tunnel_l = gr_l ? gr_l->find<tunnel_t>() : NULL;
78 				if(  tunnel_l  &&  tunnel_l->get_desc() == desc  &&  gr_l->get_grund_hang() == hang  ) {
79 					broad_type += 1;
80 					if(  !(tunnel_l->get_broad_type() & 2)  ) {
81 						tunnel_l->calc_image();
82 					}
83 				}
84 				const grund_t *gr_r = welt->lookup(get_pos() - dir);
85 				tunnel_t* tunnel_r = gr_r ? gr_r->find<tunnel_t>() : NULL;
86 				if(  tunnel_r  &&  tunnel_r->get_desc() == desc  &&  gr_r->get_grund_hang() == hang  ) {
87 					broad_type += 2;
88 					if(  !(tunnel_r->get_broad_type() & 1)  ) {
89 						tunnel_r->calc_image();
90 					}
91 				}
92 			}
93 		}
94 
95 		set_image( desc->get_background_id( hang, get_pos().z >= welt->get_snowline()  ||  welt->get_climate( get_pos().get_2d() ) == arctic_climate, broad_type ) );
96 		set_foreground_image( desc->get_foreground_id( hang, get_pos().z >= welt->get_snowline()  ||  welt->get_climate( get_pos().get_2d() ) == arctic_climate, broad_type ) );
97 	}
98 	else {
99 		set_image( IMG_EMPTY );
100 		set_foreground_image( IMG_EMPTY );
101 	}
102 #ifdef MULTI_THREAD
103 	pthread_mutex_unlock( &tunnel_calc_image_mutex );
104 #endif
105 }
106 
107 
108 
rdwr(loadsave_t * file)109 void tunnel_t::rdwr(loadsave_t *file)
110 {
111 	xml_tag_t t( file, "tunnel_t" );
112 	obj_t::rdwr(file);
113 	if(  file->is_version_atleast(99, 1) ) {
114 		char  buf[256];
115 		if(  file->is_loading()  ) {
116 			file->rdwr_str(buf, lengthof(buf));
117 			desc = tunnel_builder_t::get_desc(buf);
118 			if(  desc==NULL  ) {
119 				desc = tunnel_builder_t::get_desc(translator::compatibility_name(buf));
120 			}
121 			if(  desc==NULL  ) {
122 				welt->add_missing_paks( buf, karte_t::MISSING_WAY );
123 			}
124 		}
125 		else {
126 			strcpy( buf, desc->get_name() );
127 			file->rdwr_str(buf,0);
128 		}
129 	}
130 }
131 
132 
finish_rd()133 void tunnel_t::finish_rd()
134 {
135 	const grund_t *gr = welt->lookup(get_pos());
136 	player_t *player=get_owner();
137 
138 	if(desc==NULL) {
139 		// find a matching desc
140 		if (gr->get_weg_nr(0)==NULL) {
141 			// no way? underground powerline
142 			if (gr->get_leitung()) {
143 				desc = tunnel_builder_t::get_tunnel_desc(powerline_wt, 1, 0);
144 			}
145 			// no tunnel -> use dummy road tunnel
146 			if (desc==NULL) {
147 				desc = tunnel_builder_t::get_tunnel_desc(road_wt, 1, 0);
148 			}
149 		}
150 		else {
151 			desc = tunnel_builder_t::get_tunnel_desc(gr->get_weg_nr(0)->get_desc()->get_wtyp(), 450, 0);
152 			if(  desc == NULL  ) {
153 				dbg->error( "tunnel_t::finish_rd()", "Completely unknown tunnel for this waytype: Lets use a rail tunnel!" );
154 				desc = tunnel_builder_t::get_tunnel_desc(track_wt, 1, 0);
155 			}
156 		}
157 	}
158 
159 	if(player) {
160 		// change maintenance
161 		weg_t *weg = gr->get_weg(desc->get_waytype());
162 		if(weg) {
163 			weg->set_max_speed(desc->get_topspeed());
164 			player_t::add_maintenance( player, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
165 		}
166 		leitung_t *lt = gr->get_leitung();
167 		if(lt) {
168 			player_t::add_maintenance( player, -lt->get_desc()->get_maintenance(), powerline_wt );
169 		}
170 		player_t::add_maintenance( player,  desc->get_maintenance(), desc->get_finance_waytype() );
171 	}
172 }
173 
174 
175 // correct speed and maintenance
cleanup(player_t * player2)176 void tunnel_t::cleanup( player_t *player2 )
177 {
178 	player_t *player = get_owner();
179 	if(player) {
180 		// inside tunnel => do nothing but change maintenance
181 		const grund_t *gr = welt->lookup(get_pos());
182 		if(gr) {
183 			weg_t *weg = gr->get_weg( desc->get_waytype() );
184 			if(weg)	{
185 				weg->set_max_speed( weg->get_desc()->get_topspeed() );
186 				player_t::add_maintenance( player,  weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
187 			}
188 			player_t::add_maintenance( player,  -desc->get_maintenance(), desc->get_finance_waytype() );
189 		}
190 	}
191 	player_t::book_construction_costs(player2, -desc->get_price(), get_pos().get_2d(), desc->get_finance_waytype() );
192 }
193 
194 
set_image(image_id b)195 void tunnel_t::set_image( image_id b )
196 {
197 	mark_image_dirty( image, 0 );
198 	mark_image_dirty( b, 0 );
199 	image = b;
200 }
201 
202 
set_foreground_image(image_id b)203 void tunnel_t::set_foreground_image( image_id b )
204 {
205 	mark_image_dirty( foreground_image, 0 );
206 	mark_image_dirty( b, 0 );
207 	foreground_image = b;
208 }
209 
210 
211 // returns NULL, if removal is allowed
212 // players can remove public owned ways
is_deletable(const player_t * player)213 const char *tunnel_t::is_deletable(const player_t *player)
214 {
215 	if (get_player_nr()==welt->get_public_player()->get_player_nr()) {
216 		return NULL;
217 	}
218 	else {
219 		return obj_t::is_deletable(player);
220 	}
221 }
222