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