1 /*
2  * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic license.
5  * (see license.txt)
6  */
7 
8 #include <stdio.h>
9 
10 #include "../simdebug.h"
11 #include "../simworld.h"
12 #include "../display/simimg.h"
13 
14 #include "../utils/simrandom.h"
15 #include "../boden/grund.h"
16 #include "../dataobj/loadsave.h"
17 #include "../dataobj/translator.h"
18 #include "../utils/cbuffer_t.h"
19 
20 #include "simpeople.h"
21 #include "../descriptor/pedestrian_desc.h"
22 
23 static uint32 const strecke[] = { 6000, 11000, 15000, 20000, 25000, 30000, 35000, 40000 };
24 
25 static weighted_vector_tpl<const pedestrian_desc_t*> list_timeline;
26 stringhashtable_tpl<const pedestrian_desc_t *> pedestrian_t::table;
27 
28 
register_desc(const pedestrian_desc_t * desc)29 bool pedestrian_t::register_desc(const pedestrian_desc_t *desc)
30 {
31 	if(  table.remove(desc->get_name())  ) {
32 		dbg->doubled( "pedestrian", desc->get_name() );
33 	}
34 	table.put(desc->get_name(), desc);
35 	return true;
36 }
37 
38 
successfully_loaded()39 bool pedestrian_t::successfully_loaded()
40 {
41 	if (table.empty()) {
42 		DBG_MESSAGE("pedestrian_t", "No pedestrians found - feature disabled");
43 	}
44 	return true;
45 }
46 
47 
compare_pedestrian_desc(const pedestrian_desc_t * a,const pedestrian_desc_t * b)48 static bool compare_pedestrian_desc(const pedestrian_desc_t* a, const pedestrian_desc_t* b)
49 {
50 	int diff = a->get_intro_year_month() - b->get_intro_year_month();
51 	if (diff == 0) {
52 		/* same Level - we introduce an artificial, but unique resort
53 		* on the induced name. */
54 		diff = strcmp(a->get_name(), b->get_name());
55 	}
56 	return diff < 0;
57 }
58 
59 
pedestrian_t(loadsave_t * file)60 pedestrian_t::pedestrian_t(loadsave_t *file)
61  : road_user_t()
62 {
63 	animation_steps = 0;
64 	on_left = false;
65 	steps_offset = 0;
66 	rdwr(file);
67 	if(desc) {
68 		welt->sync.add(this);
69 		ped_offset = desc->get_offset();
70 	}
71 	calc_disp_lane();
72 }
73 
74 
build_timeline_list(karte_t * welt)75 void pedestrian_t::build_timeline_list(karte_t *welt)
76 {
77 	// this list will contain all citycars
78 	list_timeline.clear();
79 	vector_tpl<const pedestrian_desc_t*> temp_liste(0);
80 	if(  !table.empty()  ) {
81 		const int month_now = welt->get_current_month();
82 
83 		// check for every citycar, if still ok ...
84 		FOR(stringhashtable_tpl<pedestrian_desc_t const*>, const& i, table) {
85 			pedestrian_desc_t const* const info = i.value;
86 			const int intro_month = info->get_intro_year_month();
87 			const int retire_month = info->get_retire_year_month();
88 
89 			if (!welt->use_timeline() || (intro_month <= month_now && month_now < retire_month)) {
90 				temp_liste.insert_ordered( info, compare_pedestrian_desc );
91 			}
92 		}
93 	}
94 	list_timeline.resize( temp_liste.get_count() );
95 	FOR(vector_tpl<pedestrian_desc_t const*>, const i, temp_liste) {
96 		list_timeline.append(i, i->get_distribution_weight());
97 	}
98 }
99 
100 
101 
list_empty()102 bool pedestrian_t::list_empty()
103 {
104 	return list_timeline.empty();
105 }
106 
107 
108 
pedestrian_t(grund_t * gr)109 pedestrian_t::pedestrian_t(grund_t *gr) :
110 	road_user_t(gr, simrand(65535)),
111 	desc(pick_any_weighted(list_timeline))
112 {
113 	animation_steps = 0;
114 	on_left = simrand(2) > 0;
115 	steps_offset = 0;
116 	time_to_life = pick_any(strecke);
117 	ped_offset = desc->get_offset();
118 	calc_image();
119 	calc_disp_lane();
120 }
121 
122 
~pedestrian_t()123 pedestrian_t::~pedestrian_t()
124 {
125 	if(  time_to_life>0  ) {
126 		welt->sync.remove( this );
127 	}
128 }
129 
130 
calc_image()131 void pedestrian_t::calc_image()
132 {
133 	set_image(desc->get_image_id(ribi_t::get_dir(get_direction())));
134 }
135 
136 
get_image() const137 image_id pedestrian_t::get_image() const
138 {
139 	if (desc->get_steps_per_frame() > 0) {
140 		uint16 frame = ((animation_steps + steps) / desc->get_steps_per_frame()) % desc->get_animation_count(ribi_t::get_dir(direction));
141 		return desc->get_image_id(ribi_t::get_dir(get_direction()), frame);
142 	}
143 	else {
144 		return image;
145 	}
146 }
147 
148 
rdwr(loadsave_t * file)149 void pedestrian_t::rdwr(loadsave_t *file)
150 {
151 	xml_tag_t f( file, "fussgaenger_t" );
152 
153 	road_user_t::rdwr(file);
154 
155 	if(!file->is_loading()) {
156 		const char *s = desc->get_name();
157 		file->rdwr_str(s);
158 	}
159 	else {
160 		char s[256];
161 		file->rdwr_str(s, lengthof(s));
162 		desc = table.get(s);
163 		// unknown pedestrian => create random new one
164 		if(desc == NULL  &&  !list_timeline.empty()  ) {
165 			desc = pick_any_weighted(list_timeline);
166 		}
167 	}
168 
169 	if(file->is_version_less(89, 4)) {
170 		time_to_life = pick_any(strecke);
171 	}
172 
173 	if (file->is_version_atleast(120, 6)) {
174 		file->rdwr_short(steps_offset);
175 		file->rdwr_bool(on_left);
176 	}
177 
178 	if (file->is_loading()) {
179 		calc_disp_lane();
180 	}
181 }
182 
calc_disp_lane()183 void pedestrian_t::calc_disp_lane()
184 {
185 	// walking in the back or the front
186 	ribi_t::ribi test_dir = on_left ? ribi_t::northeast : ribi_t::southwest;
187 	disp_lane = direction & test_dir ? 0 : 4;
188 }
189 
190 
rotate90()191 void pedestrian_t::rotate90()
192 {
193 	road_user_t::rotate90();
194 	calc_disp_lane();
195 }
196 
197 // create a number (count) of pedestrians (if possible)
generate_pedestrians_at(const koord3d k,int & count)198 void pedestrian_t::generate_pedestrians_at(const koord3d k, int &count)
199 {
200 	if (list_timeline.empty()) {
201 		return;
202 	}
203 
204 	grund_t* bd = welt->lookup(k);
205 	if (bd) {
206 		const weg_t* weg = bd->get_weg(road_wt);
207 
208 		// we do not start on crossings (not overrunning pedestrians please
209 		if (weg && ribi_t::is_twoway(weg->get_ribi_unmasked())) {
210 			// we create maximal 4 pedestrians here for performance reasons
211 			for (int i = 0; i < 4 && count > 0; i++) {
212 				pedestrian_t* fg = new pedestrian_t(bd);
213 				bool ok = bd->obj_add(fg) != 0;	// 256 limit reached
214 				if (ok) {
215 					fg->calc_height(bd);
216 					if (i > 0) {
217 						// walk a little
218 						fg->sync_step( (i & 3) * 64 * 24);
219 					}
220 					welt->sync.add(fg);
221 					count--;
222 				}
223 				else {
224 					// delete it, if we could not put it on the map
225 					fg->set_flag(obj_t::not_on_map);
226 					// do not try to delete it from sync-list
227 					fg->time_to_life = 0;
228 					delete fg;
229 					return; // it is pointless to try again
230 				}
231 			}
232 		}
233 	}
234 }
235 
236 
sync_step(uint32 delta_t)237 sync_result pedestrian_t::sync_step(uint32 delta_t)
238 {
239 	time_to_life -= delta_t;
240 
241 	if (time_to_life>0) {
242 		weg_next += 128*delta_t;
243 		weg_next -= do_drive( weg_next );
244 		return time_to_life>0 ? SYNC_OK : SYNC_DELETE;
245 	}
246 	return SYNC_DELETE;
247 }
248 
249 
hop_check()250 grund_t* pedestrian_t::hop_check()
251 {
252 	grund_t *from = welt->lookup(pos_next);
253 	if(!from) {
254 		time_to_life = 0;
255 		return NULL;
256 	}
257 
258 	// find the allowed directions
259 	const weg_t *weg = from->get_weg(road_wt);
260 	if(weg==NULL) {
261 		// no road anymore: destroy it
262 		time_to_life = 0;
263 		return NULL;
264 	}
265 	return from;
266 }
267 
268 
hop(grund_t * gr)269 void pedestrian_t::hop(grund_t *gr)
270 {
271 	koord3d from = get_pos();
272 
273 	// hop
274 	leave_tile();
275 	set_pos(gr->get_pos());
276 	// no need to call enter_tile();
277 	gr->obj_add(this);
278 
279 	// determine pos_next
280 	const weg_t *weg = gr->get_weg(road_wt);
281 	// new target
282 	grund_t *to = NULL;
283 	// current single direction
284 	ribi_t::ribi current_direction = get_direction();
285 	if (!ribi_t::is_single(current_direction)) {
286 		current_direction = ribi_type(from, get_pos());
287 	}
288 	// ribi opposite to current direction
289 	ribi_t::ribi reverse_direction = ribi_t::reverse_single( current_direction );
290 	// all possible directions
291 	ribi_t::ribi ribi = weg->get_ribi_unmasked() & (~reverse_direction);
292 	// randomized offset
293 	const uint8 offset = (ribi > 0  &&  ribi_t::is_single(ribi)) ? 0 : simrand(4);
294 
295 	ribi_t::ribi new_direction;
296 	for(uint r = 0; r < 4; r++) {
297 		new_direction = ribi_t::nsew[ (r+offset) & 3];
298 
299 		if(  (ribi & new_direction)!=0  &&  gr->get_neighbour(to, road_wt, new_direction) ) {
300 			// this is our next target
301 			break;
302 		}
303 	}
304 	steps_offset = 0;
305 
306 	if (to) {
307 		pos_next = to->get_pos();
308 
309 		if (new_direction == current_direction) {
310 			// going straight
311 			direction = calc_set_direction(get_pos(), pos_next);
312 		}
313 		else {
314 			ribi_t::ribi turn_ribi = on_left ? ribi_t::rotate90l(current_direction) : ribi_t::rotate90(current_direction);
315 
316 			if (turn_ribi == new_direction) {
317 				// short diagonal (turn but do not cross street)
318 				direction = calc_set_direction(from, pos_next);
319 				steps_next = (ped_offset*181) / 128; // * sqrt(2)
320 				steps_offset = 0;
321 			}
322 			else {
323 				// do not cross street diagonally, change side
324 				on_left = !on_left;
325 				direction = calc_set_direction(get_pos(), pos_next);
326 			}
327 		}
328 	}
329 	else {
330 		// dead end, turn
331 		pos_next = from;
332 		direction = calc_set_direction(get_pos(), pos_next);
333 		steps_offset = VEHICLE_STEPS_PER_TILE - ped_offset;
334 		steps_next   = ped_offset;
335 		on_left = !on_left;
336 	}
337 
338 	calc_disp_lane();
339 	// carry over remainder to next tile for continuous animation during straight movement
340 	uint16 steps_per_animation = desc->get_steps_per_frame() * desc->get_animation_count(ribi_t::get_dir(direction));
341 	if (steps_per_animation > 0) {
342 		animation_steps = (animation_steps + steps_next + 1) % steps_per_animation;
343 	}
344 	else {
345 		animation_steps = 0;
346 	}
347 
348 	calc_image();
349 }
350 
get_screen_offset(int & xoff,int & yoff,const sint16 raster_width) const351 void pedestrian_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const
352 {
353 	// vehicles needs finer steps to appear smoother
354 	sint32 display_steps = (uint32)(steps + steps_offset)*(uint16)raster_width;
355 	if(  dx && dy  ) {
356 		display_steps &= 0xFFFFFC00;
357 	}
358 	else {
359 		display_steps = (display_steps*diagonal_multiplier)>>10;
360 	}
361 	xoff += (display_steps*dx) >> 10;
362 	yoff += ((display_steps*dy) >> 10) + (get_hoff(raster_width))/(4*16);
363 
364 	if (on_left) {
365 		sint32 left_off_steps = ( (VEHICLE_STEPS_PER_TILE - 2*ped_offset)*(uint16)raster_width ) & 0xFFFFFC00;
366 
367 		if (dx*dy==0) {
368 			// diagonal
369 			left_off_steps /= 2;
370 		}
371 		// turn left (dx,dy) increments
372 		xoff += (left_off_steps*2*dy) >> 10;
373 		yoff -= (left_off_steps*dx) >> (10+1);
374 	}
375 }
376 
377 
info(cbuffer_t & buf) const378 void pedestrian_t::info(cbuffer_t & buf) const
379 {
380 	char const* const owner = translator::translate("Kein Besitzer\n");
381 	buf.append(owner);
382 
383 	if (char const* const maker = get_desc()->get_copyright()) {
384 		buf.printf(translator::translate("Constructed by %s"), maker);
385 	}
386 }
387