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