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 "../simdebug.h"
9 #include "../simworld.h"
10 #include "../simobj.h"
11 #include "../display/simimg.h"
12 #include "../player/simplay.h"
13 #include "../simtypes.h"
14 
15 #include "../boden/grund.h"
16 #include "../descriptor/groundobj_desc.h"
17 
18 #include "../utils/cbuffer_t.h"
19 #include "../utils/simstring.h"
20 #include "../utils/simrandom.h"
21 
22 #include "../dataobj/loadsave.h"
23 #include "../dataobj/translator.h"
24 #include "../dataobj/environment.h"
25 #include "../dataobj/freelist.h"
26 
27 
28 #include "groundobj.h"
29 
30 /******************************** static routines for desc management ****************************************************************/
31 
32 vector_tpl<const groundobj_desc_t *> groundobj_t::groundobj_typen(0);
33 
34 stringhashtable_tpl<groundobj_desc_t *> groundobj_t::desc_table;
35 
36 
compare_groundobj_desc(const groundobj_desc_t * a,const groundobj_desc_t * b)37 bool compare_groundobj_desc(const groundobj_desc_t* a, const groundobj_desc_t* b)
38 {
39 	return strcmp(a->get_name(), b->get_name())<0;
40 }
41 
42 
successfully_loaded()43 bool groundobj_t::successfully_loaded()
44 {
45 	groundobj_typen.resize(desc_table.get_count());
46 	FOR(stringhashtable_tpl<groundobj_desc_t*>, const& i, desc_table) {
47 		groundobj_typen.insert_ordered(i.value, compare_groundobj_desc);
48 	}
49 	// iterate again to assign the index
50 	FOR(stringhashtable_tpl<groundobj_desc_t*>, const& i, desc_table) {
51 		i.value->index = groundobj_typen.index_of(i.value);
52 	}
53 
54 	if(desc_table.empty()) {
55 		groundobj_typen.append( NULL );
56 		DBG_MESSAGE("groundobj_t", "No groundobj found - feature disabled");
57 	}
58 	return true;
59 }
60 
61 
register_desc(groundobj_desc_t * desc)62 bool groundobj_t::register_desc(groundobj_desc_t *desc)
63 {
64 	assert(desc->get_speed()==0);
65 	// remove duplicates
66 	if(  desc_table.remove( desc->get_name() )  ) {
67 		dbg->doubled( "groundobj", desc->get_name() );
68 	}
69 	desc_table.put(desc->get_name(), desc );
70 	return true;
71 }
72 
73 
74 /* also checks for distribution values
75  * @author prissi
76  */
random_groundobj_for_climate(climate_bits cl,slope_t::type slope)77 const groundobj_desc_t *groundobj_t::random_groundobj_for_climate(climate_bits cl, slope_t::type slope  )
78 {
79 	// none there
80 	if(  desc_table.empty()  ) {
81 		return NULL;
82 	}
83 
84 	int weight = 0;
85 	FOR(  vector_tpl<groundobj_desc_t const*>,  const i,  groundobj_typen  ) {
86 		if(  i->is_allowed_climate_bits(cl)  &&  (slope == slope_t::flat  ||  (i->get_phases() >= slope  &&  i->get_image_id(0,slope)!=IMG_EMPTY  )  )  ) {
87 			weight += i->get_distribution_weight();
88 		}
89 	}
90 
91 	// now weight their distribution
92 	if(  weight > 0  ) {
93 		const int w=simrand(weight);
94 		weight = 0;
95 		FOR(vector_tpl<groundobj_desc_t const*>, const i, groundobj_typen) {
96 			if(  i->is_allowed_climate_bits(cl)  &&  (slope == slope_t::flat  ||  (i->get_phases() >= slope  &&  i->get_image_id(0,slope)!=IMG_EMPTY  )  )  ) {
97 				weight += i->get_distribution_weight();
98 				if(weight>=w) {
99 					return i;
100 				}
101 			}
102 		}
103 	}
104 	return NULL;
105 }
106 
107 
108 
109 /******************************* end of static ******************************************/
110 
111 
112 
113 // recalculates only the seasonal image
calc_image()114 void groundobj_t::calc_image()
115 {
116 	const groundobj_desc_t *desc=get_desc();
117 	const sint16 seasons = desc->get_seasons()-1;
118 	uint8 season=0;
119 
120 	// two possibilities
121 	switch(seasons) {
122 				// summer only
123 		case 0: season = 0;
124 				break;
125 				// summer, snow
126 		case 1: season = welt->get_snowline() <= get_pos().z  ||  welt->get_climate( get_pos().get_2d() ) == arctic_climate;
127 				break;
128 				// summer, winter, snow
129 		case 2: season = (welt->get_snowline() <= get_pos().z  ||  welt->get_climate( get_pos().get_2d() ) == arctic_climate) ? 2 : welt->get_season() == 1;
130 				break;
131 		default: if(  welt->get_snowline() <= get_pos().z  ||  welt->get_climate( get_pos().get_2d() ) == arctic_climate  ) {
132 					season = seasons;
133 				}
134 				else {
135 					// resolution 1/8th month (0..95)
136 					const uint32 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_ticks()>>(welt->ticks_per_world_month_shift-3))&7) + 1;
137 					season = (seasons*yearsteps-1)/96;
138 				}
139 				break;
140 	}
141 	// check for slopes?
142 	uint16 phase = 0;
143 	if(desc->get_phases()>1) {
144 		phase = welt->lookup(get_pos())->get_grund_hang();
145 	}
146 	image = get_desc()->get_image_id( season, phase );
147 }
148 
149 
groundobj_t(loadsave_t * file)150 groundobj_t::groundobj_t(loadsave_t *file) : obj_t()
151 {
152 	rdwr(file);
153 }
154 
155 
groundobj_t(koord3d pos,const groundobj_desc_t * b)156 groundobj_t::groundobj_t(koord3d pos, const groundobj_desc_t *b ) : obj_t(pos)
157 {
158 	groundobjtype = groundobj_typen.index_of(b);
159 	calc_image();
160 }
161 
162 
check_season(const bool)163 bool groundobj_t::check_season(const bool)
164 {
165 	const image_id old_image = get_image();
166 	calc_image();
167 
168 	if(  get_image() != old_image  ) {
169 		mark_image_dirty( get_image(), 0 );
170 	}
171 	return true;
172 }
173 
174 
rdwr(loadsave_t * file)175 void groundobj_t::rdwr(loadsave_t *file)
176 {
177 	xml_tag_t d( file, "groundobj_t" );
178 
179 	obj_t::rdwr(file);
180 
181 	if(file->is_saving()) {
182 		const char *s = get_desc()->get_name();
183 		file->rdwr_str(s);
184 	}
185 	else {
186 		char bname[128];
187 		file->rdwr_str(bname, lengthof(bname));
188 		groundobj_desc_t *desc = desc_table.get( bname );
189 		if(  desc==NULL  ) {
190 			desc =  desc_table.get( translator::compatibility_name( bname ) );
191 		}
192 		if(  desc==NULL  ) {
193 			groundobjtype = simrand(groundobj_typen.get_count());
194 		}
195 		else {
196 			groundobjtype = desc->get_index();
197 		}
198 		// if not there, desc will be zero
199 	}
200 }
201 
202 
203 /**
204  * �ffnet ein neues Beobachtungsfenster f�r das Objekt.
205  * @author Hj. Malthaner
206  */
show_info()207 void groundobj_t::show_info()
208 {
209 	if(env_t::tree_info) {
210 		obj_t::show_info();
211 	}
212 }
213 
214 
215 /**
216  * @return Einen Beschreibungsstring f�r das Objekt, der z.B. in einem
217  * Beobachtungsfenster angezeigt wird.
218  * @author Hj. Malthaner
219  */
info(cbuffer_t & buf) const220 void groundobj_t::info(cbuffer_t & buf) const
221 {
222 	obj_t::info(buf);
223 
224 	buf.append(translator::translate(get_desc()->get_name()));
225 	if (char const* const maker = get_desc()->get_copyright()) {
226 		buf.append("\n");
227 		buf.printf(translator::translate("Constructed by %s"), maker);
228 	}
229 	buf.append("\n");
230 	buf.append(translator::translate("cost for removal"));
231 	char buffer[128];
232 	money_to_string( buffer, get_desc()->get_price()/100.0 );
233 	buf.append( buffer );
234 }
235 
236 
cleanup(player_t * player)237 void groundobj_t::cleanup(player_t *player)
238 {
239 	player_t::book_construction_costs(player, -get_desc()->get_price(), get_pos().get_2d(), ignore_wt);
240 	mark_image_dirty( get_image(), 0 );
241 }
242 
243 
operator new(size_t)244 void *groundobj_t::operator new(size_t /*s*/)
245 {
246 	return freelist_t::gimme_node(sizeof(groundobj_t));
247 }
248 
249 
operator delete(void * p)250 void groundobj_t::operator delete(void *p)
251 {
252 	freelist_t::putback_node(sizeof(groundobj_t),p);
253 }
254