Skyscraper 2.0
person.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Person Object
3 The Skyscraper Project - Version 2.0
4 Copyright (C)2004-2024 Ryan Thoryk
5 https://www.skyscrapersim.net
6 https://sourceforge.net/projects/skyscraper/
7 Contact - ryan@skyscrapersim.net
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*/
23
24#include "globals.h"
25#include "sbs.h"
26#include "floor.h"
27#include "elevator.h"
28#include "elevatorcar.h"
29#include "callstation.h"
30#include "control.h"
31#include "route.h"
32#include "random.h"
33#include "timer.h"
34#include "profiler.h"
35#include "person.h"
36
37namespace SBS {
38
39//random call timer
41{
42public:
44 Timer(const std::string &name, Person *parent) : TimerObject(parent, name)
45 {
46 this->parent = parent;
47 }
48 virtual void Notify();
49};
50
51Person::Person(Object *parent, const std::string &name, int floor, bool service_access) : Object(parent)
52{
53 //creates a person object, used for random traffic simulations
54
55 //set up SBS object
56 SetValues("Person", name, false);
57
58 current_floor = floor;
59 dest_floor = 0;
60 this->service_access = service_access;
61 RandomProbability = sbs->GetConfigInt("Skyscraper.SBS.Person.RandomProbability", 20);
62 RandomFrequency = sbs->GetConfigFloat("Skyscraper.SBS.Person.RandomFrequency", 5);
63
64 //initialize random number generators
65 rnd_time = new RandomGen((unsigned int)(time(0) + GetNumber()));
66 rnd_dest = new RandomGen((unsigned int)(time(0) + GetNumber() + 1));
67
68 //create timer
69 random_timer = new Timer("Random Timer", this);
70
71 SetFloor(floor);
72 EnableLoop(true);
73}
74
76{
77 //delete timer
78 if (random_timer)
79 {
81 delete random_timer;
82 }
83 random_timer = 0;
84
85 //delete routes
86 Stop();
87
88 //delete random number generators
89 if (rnd_time)
90 delete rnd_time;
91 rnd_time = 0;
92
93 if (rnd_dest)
94 delete rnd_dest;
95 rnd_dest = 0;
96
97 if (sbs->FastDelete == false && parent_deleting == false)
98 sbs->RemovePerson(this);
99}
100
102{
103 //enable or disable timer
104 if (value == true)
105 {
106 random_timer->Start(int(RandomFrequency * 1000), false);
107 Report("Random activity enabled");
108 }
109 else
110 {
112 Report("Random activity disabled");
113 }
114}
115
117{
118 return (int)rnd_dest->Get(sbs->GetTotalFloors() - 1) - sbs->Basements;
119}
120
121void Person::GotoFloor(int floor)
122{
123 //exit if a route is already active
124 if (IsRouteActive() == true)
125 return;
126
127 Floor *origfloor = sbs->GetFloor(current_floor);
128 Floor *newfloor = sbs->GetFloor(floor);
129
130 //verify floors
131 if (!origfloor || !newfloor)
132 return;
133
134 //make sure we're going to a different floor
135 if (floor == current_floor)
136 return;
137
138 dest_floor = floor;
139
140 Report("Heading to floor " + newfloor->ID);
141
142 //get route to floor, as a list of elevators
143 std::vector<ElevatorRoute*> elevators = sbs->GetRouteToFloor(current_floor, dest_floor, service_access);
144
145 if (elevators.empty() == true)
146 {
147 Report("No route found to floor " + newfloor->ID);
148 return;
149 }
150
151 if (sbs->Verbose == true)
152 Report("Routing table:");
153
154 //create a new route table entry for each elevator in list
155 for (size_t i = 0; i < elevators.size(); i++)
156 {
157 Elevator *elevator = elevators[i]->car->GetElevator();
158 if (sbs->Verbose == true)
159 Report(ToString((int)i) + ": Elevator " + ToString(elevator->Number) + " - floor selection " + ToString(elevators[i]->floor_selection) + " - elevator name: " + elevator->Name);
160
161 RouteEntry route_entry;
162 route_entry.elevator_route = elevators[i];
163 route_entry.callstation = 0;
164 route_entry.call_made = 0;
165 route_entry.floor_selected = false;
166 route_entry.destination = false;
167 route_entry.in_elevator = false;
168 route.emplace_back(route_entry);
169 }
170}
171
173{
174 SBS_PROFILE("Person::Loop");
175
176 ProcessRoute();
177}
178
180{
181 if (IsRouteActive() == false)
182 return;
183
184 SBS_PROFILE("Person::ProcessRoute");
185
186 Floor *floor_obj = sbs->GetFloor(current_floor);
187
188 if (!floor_obj)
189 return;
190
191 ElevatorCar *car = route[0].elevator_route->car;
192 int floor_selection = route[0].elevator_route->floor_selection;
193
194 if (!car)
195 return;
196
197 Elevator *elevator = car->GetElevator();
198
199 route[0].destination = elevator->GetDestinationDispatch();
200
201 //if a call has not been made, press first elevator's associated call button
202 if (route[0].call_made == 0)
203 {
204 route[0].callstation = floor_obj->GetCallStationForElevator(elevator->Number);
205 CallStation *station = route[0].callstation;
206
207 bool result = false;
208
209 if (station && route[0].destination == false)
210 {
211 Report("Pressing call button for elevator " + ToString(elevator->Number));
212
213 if (floor_selection > current_floor)
214 {
215 result = station->Press(true);
216 route[0].call_made = 1;
217 }
218 else
219 {
220 result = station->Press(false);
221 route[0].call_made = -1;
222 }
223 }
224
225 if (station && route[0].destination == true)
226 {
227 Report("Pressing " + ToString(floor_selection) + " on call station for elevator " + ToString(elevator->Number));
228
229 result = station->SelectFloor(floor_selection);
230 route[0].floor_selected = true;
231
232 if (floor_selection > current_floor)
233 route[0].call_made = 1;
234 else
235 route[0].call_made = -1;
236 }
237
238 //stop route if call can't be made
239 if (result == false)
240 {
241 Report("Can't call elevator " + ToString(elevator->Number));
242 Stop();
243 }
244
245 return;
246 }
247
248 //if a call has been made, wait for an elevator to arrive
249 //then press floor button for standard elevators, or ride elevator for destination dispatch
250 if (route[0].floor_selected == false || (route[0].destination == true && route[0].in_elevator == false))
251 {
252 CallStation *station = route[0].callstation;
253
254 if (!station)
255 return;
256
257 bool direction = (floor_selection > current_floor);
258 int number = 0;
259 if (station)
260 {
261 if (route[0].destination == false)
262 number = station->GetElevatorArrivedStandard(current_floor, direction);
263 else
264 number = station->GetElevatorArrived(current_floor, floor_selection);
265 }
266
267 if (number > 0)
268 {
269 //if elevator has arrived at the called floor, press related floor button if using a call button
270 //otherwise wait for destination dispatch mode
271
272 Elevator *elevator = sbs->GetElevator(number);
273 if (elevator)
274 {
275 ElevatorCar *car = elevator->GetCarForFloor(current_floor);
276 if (car)
277 {
278 //have elevator route use arrived elevator
279 route[0].elevator_route->car = car;
280
281 //person is in elevator
282 route[0].in_elevator = true;
283
284 Floor *floor = sbs->GetFloor(floor_selection);
285
286 if (!floor)
287 return;
288
289 if (route[0].destination == false)
290 {
291 //wait for elevator doors to open before pressing button
292 if (car->AreDoorsOpen() == true)
293 {
294 Report("Pressing elevator button for floor " + floor->ID);
295
296 Control *control = car->GetFloorButton(floor_selection);
297
298 if (control)
299 {
300 if (control->IsLocked() == false)
301 {
302 //press floor button
303 control->Press();
304 route[0].floor_selected = true;
305 return;
306 }
307 }
308
309 //stop route if floor button is locked, or does not exist
310 Report("Can't press elevator button for floor " + floor->ID);
311 Stop();
312 return;
313 }
314 }
315 else
316 {
317 //destination dispatch mode
318 Report("Waiting in elevator for floor " + floor->ID);
319 }
320 }
321 }
322 }
323 else
324 {
325 //if call has become invalid, stop route
326 if (station)
327 {
328 if ((direction == true && station->GetUpStatus() == false) ||
329 (direction == false && station->GetDownStatus() == false))
330 {
331 Stop();
332 return;
333 }
334 }
335 }
336 }
337 else
338 {
339 //wait for the elevator to arrive at the selected floor
340
341 if (elevator->OnFloor == true && car->GetFloor() == floor_selection && car->AreDoorsOpen() == true)
342 {
343 std::string floor_status;
344
345 if (floor_selection == dest_floor)
346 floor_status = "destination";
347 else if (route[0].call_made == 2)
348 floor_status = "recall";
349 else
350 floor_status = "intermediate";
351
352 Floor *floor = sbs->GetFloor(floor_selection);
353 if (!floor)
354 return;
355
356 Report("Arrived at " + floor_status + " floor " + floor->ID);
357 current_floor = floor_selection;
358
359 if (elevator->FireServicePhase1 != 1)
360 {
361 //erase first route entry
362 delete route[0].elevator_route;
363 route.erase(route.begin());
364 }
365 else
366 {
367 //if fire phase 1 is enabled, stop all routes and exit
368 Stop();
369 }
370 return;
371 }
372 else if (elevator->InServiceMode() == true)
373 {
374 if (elevator->FireServicePhase1 == 1)
375 {
376 //if fire phase 1 mode is enabled, change floor selection to recall floor
377 //in order to exit the elevator at the recall floor
378 if (floor_selection != elevator->GetActiveRecallFloor())
379 {
380 route[0].elevator_route->floor_selection = elevator->GetActiveRecallFloor();
381 route[0].call_made = 2;
382 }
383 }
384 else
385 {
386 //otherwise exit at current floor and try another elevator
387 current_floor = car->GetFloor();
388 route[0].floor_selected = false;
389 route[0].call_made = 0;
390 }
391 return;
392 }
393 else if (elevator->IsMoving == true)
394 {
395 if (current_floor != car->GetFloor())
396 current_floor = car->GetFloor();
397 }
398 }
399}
400
401void Person::Report(const std::string &message)
402{
403 //general reporting function
404 Object::Report("Person " + GetName() + ": " + message);
405}
406
407bool Person::ReportError(const std::string &message)
408{
409 //general reporting function
410 return Object::ReportError("Person " + GetName() + ": " + message);
411}
412
414{
415 //timer for random destination activity
416
417 if (parent->IsRouteActive() == true)
418 return;
419
420 int result = (int)parent->rnd_time->Get(parent->RandomProbability - 1);
421 if (result == 0)
423}
424
425void Person::SetFloor(int value)
426{
427 if (IsRouteActive() == true)
428 return;
429
430 if (!sbs->GetFloor(value))
431 return;
432
433 current_floor = value;
434 Report("On floor " + ToString(current_floor));
435}
436
438{
439 //stop route if active
440
441 //delete routes
442 if (route.empty() == false)
443 {
444 for (size_t i = 0; i < route.size(); i++)
445 {
446 delete route[i].elevator_route;
447 }
448 }
449 route.clear();
450}
451
452std::string Person::GetStatus()
453{
454 //return a string describing the person's status
455
456 if (IsRouteActive() == false)
457 {
458 Floor *floor = sbs->GetFloor(current_floor);
459 if (!floor)
460 return "";
461
462 return "Idle on floor " + floor->ID;
463 }
464
465 ElevatorCar *car = route[0].elevator_route->car;
466 int floor_selection = route[0].elevator_route->floor_selection;
467
468 Floor *floor = sbs->GetFloor(floor_selection);
469 if (!floor)
470 return "";
471
472 if (route[0].floor_selected == true && car)
473 {
474 int elevator_number = car->GetElevator()->Number;
475
476 if (car->AreDoorsOpen() == true && route[0].destination == false)
477 return "Pressed " + floor->ID + " in elevator " + ToString(elevator_number);
478 else if (route[0].in_elevator == true)
479 {
480 if (route[0].call_made != 2)
481 {
482 std::string direction;
483 if (route[0].call_made == 1)
484 direction = "Up";
485 else
486 direction = "Down";
487 return direction + " to floor " + floor->ID + " in elevator " + ToString(elevator_number);
488 }
489 else
490 return "Proceeding to recall floor";
491 }
492 }
493
494 if (route[0].destination == false)
495 {
496 if (route[0].call_made == 1)
497 return "Call button Up pressed";
498
499 if (route[0].call_made == -1)
500 return "Call button Down pressed";
501 }
502 else
503 return "Selected floor " + ToString(floor_selection) + " on call station";
504
505 return "";
506}
507
512
513}
bool Press(bool up)
bool SelectFloor(int floor)
int GetElevatorArrived(int starting_floor, int destination_floor)
int GetElevatorArrivedStandard(int floor, bool direction)
bool Press(bool reverse=false)
Definition control.cpp:386
Control * GetFloorButton(int floor)
Elevator * GetElevator()
bool AreDoorsOpen(int number=0)
int GetActiveRecallFloor()
bool GetDestinationDispatch()
std::string Name
Definition elevator.h:36
ElevatorCar * GetCarForFloor(int number, bool report_on_failure=false)
bool InServiceMode()
bool IsMoving
Definition elevator.h:60
int FireServicePhase1
Definition elevator.h:77
std::string ID
Definition floor.h:38
CallStation * GetCallStationForElevator(int elevator)
Definition floor.cpp:985
bool IsLocked()
Definition lock.cpp:66
const std::string & GetName()
Definition object.cpp:53
virtual bool ReportError(const std::string &message)
Definition object.cpp:84
virtual void Report(const std::string &message)
Definition object.cpp:78
bool parent_deleting
Definition object.h:64
int GetNumber()
Definition object.cpp:183
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
void EnableLoop(bool value)
Definition object.cpp:521
Timer(const std::string &name, Person *parent)
Definition person.cpp:44
virtual void Notify()
Definition person.cpp:413
Person * parent
Definition person.cpp:43
Real RandomFrequency
Definition person.h:78
int current_floor
Definition person.h:67
Timer * random_timer
Definition person.h:75
bool IsRouteActive()
Definition person.h:44
int RandomProbability
Definition person.h:77
void Stop()
Definition person.cpp:437
int dest_floor
Definition person.h:68
void EnableRandomActivity(bool value)
Definition person.cpp:101
int GetRandomFloor()
Definition person.cpp:116
bool ReportError(const std::string &message)
Definition person.cpp:407
RandomGen * rnd_dest
Definition person.h:33
bool service_access
Definition person.h:69
Person(Object *parent, const std::string &name, int floor, bool service_access=false)
Definition person.cpp:51
bool IsRandomActivityEnabled()
Definition person.cpp:508
void GotoFloor(int floor)
Definition person.cpp:121
std::vector< RouteEntry > route
Definition person.h:70
void Loop()
Definition person.cpp:172
void SetFloor(int value)
Definition person.cpp:425
void Report(const std::string &message)
Definition person.cpp:401
std::string GetStatus()
Definition person.cpp:452
RandomGen * rnd_time
Definition person.h:33
void ProcessRoute()
Definition person.cpp:179
float Get()
Definition random.cpp:135
Elevator * GetElevator(int number)
Definition sbs.cpp:1746
std::vector< ElevatorRoute * > GetRouteToFloor(int StartingFloor, int DestinationFloor, bool service_access=false)
Definition route.cpp:40
int GetTotalFloors()
Definition sbs.cpp:1715
Real GetConfigFloat(const std::string &key, Real default_value)
Definition sbs.cpp:3249
void RemovePerson(Person *person)
Definition sbs.cpp:4231
Floor * GetFloor(int number)
Definition sbs.cpp:1739
bool FastDelete
Definition sbs.h:188
int Basements
Definition sbs.h:159
int GetConfigInt(const std::string &key, int default_value)
Definition sbs.cpp:3232
bool Verbose
Definition sbs.h:186
bool IsRunning()
Definition timer.cpp:74
void Start(int milliseconds=-1, bool oneshot=false)
Definition timer.cpp:49
std::string ToString(int number)
Definition globals.cpp:279
#define SBS_PROFILE(name)
Definition profiler.h:131
ElevatorRoute * elevator_route
Definition person.h:59
CallStation * callstation
Definition person.h:60