Skyscraper 2.0
elevatordoor.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Elevator Door 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 "shaft.h"
30#include "mesh.h"
31#include "camera.h"
32#include "texture.h"
33#include "trigger.h"
34#include "profiler.h"
35#include "sound.h"
36#include "timer.h"
37#include "doorsystem.h"
38#include "utility.h"
39#include "elevatordoor.h"
40
41namespace SBS {
42
43//door autoclose timer
45{
46public:
50 int type; //0 = autoclose, 1 = nudge
51
52 Timer(const std::string &name, ElevatorDoor *parent, ElevatorCar *car, int Type) : TimerObject(parent, name)
53 {
54 door = parent;
55 this->car = car;
57 type = Type;
58 }
59 virtual void Notify();
60};
61
63{
64 //set up SBS object
65 SetValues("ElevatorDoor", "", false);
66
67 std::string name = "Elevator Door " + ToString(number);
68 SetName(name);
69
70 //create a new elevator door
71 Number = number;
72 this->car = car;
73 elev = car->GetElevator();
74 OpenDoor = 0;
75 OpenSpeed = sbs->GetConfigFloat("Skyscraper.SBS.Elevator.Door.OpenSpeed", 0.3);
76 WhichDoors = 0;
78 DoorTimer = sbs->GetConfigInt("Skyscraper.SBS.Elevator.Door.Timer", 5000);
79 DoorIsRunning = false;
80 index = 0;
81 previous_open = false;
82 door_changed = false;
83 quick_close = false;
84 OpenSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.OpenSound", "elevatoropen.wav");
85 CloseSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.CloseSound", "elevatorclose.wav");
86 UpChimeSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.UpChimeSound", "chime1-up.wav");
87 DownChimeSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.DownChimeSound", "chime1-down.wav");
88 EarlyUpChimeSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.EarlyUpChimeSound", "chime1-up.wav");
89 EarlyDownChimeSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.EarlyUpChimeSound", "chime1-down.wav");
90 NudgeSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.NudgeSound", "buzz.wav");
91 doors_stopped = false;
93 ShaftDoorOrigin = Vector3::ZERO;
94 nudge_enabled = false;
95 ManualSpeed = sbs->GetConfigFloat("Skyscraper.SBS.Elevator.Door.ManualSpeed", 0.2);
96 SlowSpeed = sbs->GetConfigFloat("Skyscraper.SBS.Elevator.Door.SlowSpeed", 0.5);
97 QuickClose = sbs->GetConfigInt("Skyscraper.SBS.Elevator.Door.QuickClose", 3000);
98 NudgeTimer = sbs->GetConfigFloat("Skyscraper.SBS.Elevator.Door.NudgeTimer", 30);
99 nudgesound_loaded = false;
102 sensor = 0;
103 sensor_action = 0;
104 reset_action = 0;
105 sensor_enabled = false;
106 sensor_status = false;
107 EnableSensor(sbs->GetConfigBool("Skyscraper.SBS.Elevator.Door.Sensor", true));
108 SensorSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Door.SensorSound", "");
109 DoorDirection = false;
110 EarlyUpSet = false;
111 EarlyDownSet = false;
112
113 //create main door object
114 Doors = new DoorWrapper(this, this, false);
115
116 //create timers
117 timer = new Timer("Door Close Timer", this, car, 0);
118 nudgetimer = new Timer("Nudge Timer", this, car, 1);
119
120 //initialize shaft door array
121 ShaftDoors.resize(car->ServicedFloors.size());
122 for (size_t i = 0; i < ShaftDoors.size(); i++)
123 ShaftDoors[i] = 0;
124
125 //create sound object
126 doorsound = new Sound(this, "Door Sound", true);
127 chime = new Sound(this, "Chime", true);
128 earlychime = new Sound(this, "EarlyChime", true);
129 nudgesound = new Sound(this, "Nudge Sound", true);
130}
131
133{
134 //delete shaft door objects
135 for (size_t i = 0; i < ShaftDoors.size(); i++)
136 {
137 if (ShaftDoors[i])
138 {
139 ShaftDoors[i]->parent_deleting = true;
140 delete ShaftDoors[i];
141 }
142 ShaftDoors[i] = 0;
143 }
144
145 //Destructor
146 if (timer)
147 {
148 timer->parent_deleting = true;
149 delete timer;
150 }
151 timer = 0;
152
153 if (nudgetimer)
154 {
156 delete nudgetimer;
157 }
158 nudgetimer = 0;
159
160 if (sensor)
161 {
162 sensor->parent_deleting = true;
163 delete sensor;
164 }
165 sensor = 0;
166
167 if (doorsound)
168 {
170 delete doorsound;
171 }
172 doorsound = 0;
173 if (chime)
174 {
175 chime->parent_deleting = true;
176 delete chime;
177 }
178 chime = 0;
179 if (earlychime)
180 {
182 delete earlychime;
183 }
184 if (nudgesound)
185 {
187 delete nudgesound;
188 }
189 nudgesound = 0;
190
191 //delete main doors
192 if (Doors)
193 {
194 Doors->parent_deleting = true;
195 delete Doors;
196 }
197 Doors = 0;
198
199 if (sbs->FastDelete == false)
200 {
201 //delete sensor actions
204
205 //unregister from parent
206 if (parent_deleting == false)
207 car->RemoveElevatorDoor(this);
208 }
209}
210
212{
213 //add serviced floor to door
214
215 DoorWrapper *wrapper = 0;
216
217 if (ShaftDoors.empty() == true)
218 {
219 ShaftDoors.resize(1);
220 ShaftDoors[1] = 0;
221 return;
222 }
223
224 for (size_t i = 0; i < ShaftDoors.size(); i++)
225 {
226 if (ShaftDoors[i])
227 {
228 if (ShaftDoors[i]->floor > floor)
229 {
230 //insert inside
231 ShaftDoors.insert(ShaftDoors.begin() + i, wrapper);
232 return;
233 }
234 }
235 }
236
237 //insert at top
238 ShaftDoors.emplace_back(wrapper);
239}
240
242{
243 //remove serviced floor from door
244
245 for (size_t i = 0; i < ShaftDoors.size(); i++)
246 {
247 if (ShaftDoors[i])
248 {
249 if (ShaftDoors[i]->floor == floor)
250 {
251 //delete the matching element
252 delete ShaftDoors[i];
253 ShaftDoors.erase(ShaftDoors.begin() + i);
254 return;
255 }
256 }
257 }
258}
259
260void ElevatorDoor::OpenDoorsEmergency(int whichdoors, int floor)
261{
262 //Simulates manually prying doors open.
263 //Slowly opens the elevator doors no matter where elevator is.
264 //If lined up with shaft doors, then opens the shaft doors also
265
266 //WhichDoors is the doors to move:
267 //1 = both shaft and elevator doors
268 //2 = only elevator doors
269 //3 = only shaft doors
270
271 OpenDoors(whichdoors, floor, true);
272}
273
274void ElevatorDoor::CloseDoorsEmergency(int whichdoors, int floor)
275{
276 //Simulates manually closing doors.
277 //Slowly closes the elevator doors no matter where elevator is.
278 //If lined up with shaft doors, then closes the shaft doors also
279
280 //WhichDoors is the doors to move:
281 //1 = both shaft and elevator doors
282 //2 = only elevator doors
283 //3 = only shaft doors
284
285 CloseDoors(whichdoors, floor, true);
286}
287
288void ElevatorDoor::OpenDoors(int whichdoors, int floor, bool manual)
289{
290 //Opens elevator doors
291
292 //if manual is true, then it simulates manually prying doors open,
293 //Slowly opens the elevator doors no matter where elevator is,
294 //and if lined up with shaft doors, then opens the shaft doors also
295
296 //WhichDoors is the doors to move:
297 //1 = both shaft and elevator doors
298 //2 = only elevator doors
299 //3 = only shaft doors
300
301 if (sbs->GetPower() == false && manual == false)
302 return;
303
304 //exit if trying to open doors while stopped
305 if (manual == false && doors_stopped == true)
306 {
307 car->ReportError("cannot open doors" + GetNumberText() + "; doors manually stopped");
308 return;
309 }
310
311 //exit if in nudge mode
312 if (GetNudgeStatus() == true)
313 {
314 car->ReportError("cannot open doors" + GetNumberText() + "; nudge mode enabled");
315 return;
316 }
317
318 //exit if direction changed (if doors have already switched from close to open)
319 if (door_changed == true)
320 return;
321
322 //don't open doors if emergency stop is enabled
323 if (elev->OnFloor == false && whichdoors != 3 && manual == false && elev->AutoDoors == true)
324 {
325 car->ReportError("cannot open doors" + GetNumberText() + "; emergency stop enabled");
326 return;
327 }
328
329 //exit if doors are manually moving, or automatically moving and a manual open is requested
330 if (DoorIsRunning == true && (AreDoorsMoving(2) == true || (AreDoorsMoving(1) == true && manual == true)))
331 {
332 car->ReportError("doors" + GetNumberText() + " in use");
333 return;
334 }
335
336 //check if elevator doors are already open
337 if (AreDoorsOpen() == true && whichdoors != 3 && AreDoorsMoving() == false && doors_stopped == false)
338 {
339 //reset timer if not in a service mode or waiting in a peak mode
340 if (elev->InServiceMode() == false && elev->PeakWaiting() == false)
341 {
342 car->Report("doors" + GetNumberText() + " already open; resetting timer");
343 Reset();
344 }
345 else
346 car->Report("doors" + GetNumberText() + " already open");
347 return;
348 }
349
350 //check if shaft doors are already open
351 if (whichdoors == 3)
352 {
353 //exit if other doors are running (this doesn't yet support multiple shaft door movements)
354 if (DoorIsRunning == true)
355 return;
356
357 //first make sure the shaft doors are valid
358 if (ShaftDoorsExist(floor) == false)
359 {
360 car->ReportError("Doors" + GetNumberText() + ": invalid shaft doors");
361 return;
362 }
363 if (AreShaftDoorsOpen(floor) == true)
364 {
365 car->Report("shaft doors" + GetNumberText() + " already open on floor " + ToString(floor) + " (" + sbs->GetFloor(floor)->ID + ")");
366 return;
367 }
368 else if (manual == false)
369 car->Report("opening shaft doors" + GetNumberText() + " on floor " + ToString(floor) + " (" + sbs->GetFloor(floor)->ID + ")");
370 else
371 car->Report("manually opening shaft doors" + GetNumberText() + " on floor " + ToString(floor) + " (" + sbs->GetFloor(floor)->ID + ")");
372 }
373 else if (manual == false)
374 car->Report("opening doors" + GetNumberText());
375 else
376 car->Report("manually opening doors" + GetNumberText());
377
378 if (manual == false)
379 OpenDoor = 1;
380 else
381 OpenDoor = 2;
382
383 //if both doors are selected but elevator is not on a floor, only open elevator doors
384 if (whichdoors == 1 && elev->OnFloor == false)
385 whichdoors = 2;
386
387 //change floor to elevator's destination floor if it's currently leveling to that floor
388 //this fixes an issue where the elevator might not yet be on the destination floor when this function is called
389 if (whichdoors == 1)
390 {
391 if (elev->MoveElevator == true && elev->Leveling == true)
393 else
394 floor = car->GetFloor();
395 }
396
397 //if opening both doors, exit if shaft doors don't exist
398 int index = GetManualIndex(floor);
399 if (whichdoors == 1 && ShaftDoorsExist(floor) == false && index == -1)
400 {
401 car->ReportError("can't open doors" + GetNumberText() + " - no shaft doors on " + ToString(floor));
402 OpenDoor = 0;
403 return;
404 }
405
406 WhichDoors = whichdoors;
407 ShaftDoorFloor = floor;
408 MoveDoors(true, manual);
409}
410
411void ElevatorDoor::CloseDoors(int whichdoors, int floor, bool manual)
412{
413 //Closes elevator doors
414
415 //WhichDoors is the doors to move:
416 //1 = both shaft and elevator doors
417 //2 = only elevator doors
418 //3 = only shaft doors
419
420 if (sbs->GetPower() == false && manual == false)
421 return;
422
423 //exit if trying to open doors while stopped
424 if (manual == false && doors_stopped == true)
425 {
426 car->ReportError("cannot close doors" + GetNumberText() + "; doors manually stopped");
427 return;
428 }
429
430 //do not close doors while fire service mode 1 is in recall mode and the elevator is waiting at the recall floor
431 if (manual == false && elev->FireServicePhase1 == 1 && elev->FireServicePhase2 == 0 && elev->WaitForDoors == false && elev->OnRecallFloor() == true)
432 {
433 car->ReportError("cannot close doors" + GetNumberText() + " while Fire Service Phase 1 is in recall mode");
434 return;
435 }
436
437 //do not close doors while fire service mode 2 is set to hold
438 if (manual == false && elev->FireServicePhase2 == 2)
439 {
440 car->ReportError("cannot close doors" + GetNumberText() + " while Fire Service Phase 2 is set to hold");
441 return;
442 }
443
444 //exit if doors are manually moving, or automatically moving and a manual close is requested
445 if (DoorIsRunning == true && (AreDoorsMoving(2) == true || (AreDoorsMoving(1) == true && manual == true)))
446 {
447 car->ReportError("doors" + GetNumberText() + " in use");
448 return;
449 }
450
451 //if called while doors are opening, set quick_close (causes door timer to trigger faster)
452 if (AreDoorsMoving() == true && manual == false && elev->FireServicePhase2 == 0)
453 {
454 car->Report("will close doors" + GetNumberText() + " in quick-close mode");
455 quick_close = true;
456 return;
457 }
458
459 //check if elevator doors are already closed
460 if (AreDoorsOpen() == false && whichdoors != 3 && AreDoorsMoving() == false && doors_stopped == false)
461 {
462 car->Report("doors" + GetNumberText() + " already closed");
463 return;
464 }
465
466 //check if shaft doors are already closed
467 if (whichdoors == 3)
468 {
469 //exit if other doors are running (this doesn't yet support multiple shaft door movements)
470 if (DoorIsRunning == true)
471 return;
472
473 //first make sure the shaft doors are valid
474 if (ShaftDoorsExist(floor) == false)
475 {
476 car->ReportError("Doors" + GetNumberText() + ": invalid shaft doors");
477 return;
478 }
479 if (AreShaftDoorsOpen(floor) == false && whichdoors == 3)
480 {
481 car->ReportError("shaft doors" + GetNumberText() + " already closed on floor " + ToString(floor) + " (" + sbs->GetFloor(floor)->ID + ")");
482 return;
483 }
484 else if (manual == false)
485 car->Report("closing shaft doors" + GetNumberText() + " on floor " + ToString(floor) + " (" + sbs->GetFloor(floor)->ID + ")");
486 else
487 car->Report("manually closing shaft doors" + GetNumberText() + " on floor " + ToString(floor) + " (" + sbs->GetFloor(floor)->ID + ")");
488 }
489 else if (manual == false)
490 car->Report("closing doors" + GetNumberText());
491 else
492 car->Report("manually closing doors" + GetNumberText());
493
494 if (manual == false)
495 OpenDoor = -1;
496 else
497 OpenDoor = -2;
498
499 //if both doors are selected but elevator is not on a floor, only close elevator doors
500 if (whichdoors == 1 && elev->OnFloor == false)
501 whichdoors = 2;
502
503 if (whichdoors != 3)
504 floor = car->GetFloor();
505
506 //if closing both doors, exit if shaft doors don't exist
507 int index = GetManualIndex(floor);
508 if (whichdoors == 1 && ShaftDoorsExist(floor) == false && index == -1)
509 {
510 car->ReportError("can't close doors" + GetNumberText() + " - no shaft doors on " + ToString(floor));
511 OpenDoor = 0;
512 return;
513 }
514
515 //turn off directional indicators
516 car->SetDirectionalIndicators(floor, false, false);
517
518 WhichDoors = whichdoors;
519 ShaftDoorFloor = floor;
520 MoveDoors(false, manual);
521}
522
524{
525 //stops doors that are currently moving; can only be used for manual/emergency movements
526 //this basically just resets the door internals
527
528 if (AreDoorsMoving(2) == true)
529 {
530 if (WhichDoors == 3)
531 car->Report("stopping shaft doors" + GetNumberText() + " on floor " + ToString(ShaftDoorFloor) + " (" + sbs->GetFloor(ShaftDoorFloor)->ID + ")");
532 else
533 car->Report("stopping doors" + GetNumberText());
534
535 if (WhichDoors == 1 || WhichDoors == 2)
536 Doors->StopDoors();
537 if (WhichDoors == 1 || WhichDoors == 3)
538 {
539 if (index >= 0)
540 {
541 if (ShaftDoors[index])
542 ShaftDoors[index]->StopDoors();
543 }
544 }
545
546 DoorIsRunning = false;
547 OpenDoor = 0;
548 WhichDoors = 0;
549 door_changed = false;
550 doors_stopped = true;
551
552 //disable nudge mode
553 ResetNudgeTimer(false);
554 }
555 else if (AreDoorsMoving() == true)
556 car->Report("can only stop doors" + GetNumberText() + " in manual/emergency mode");
557 else
558 car->Report("cannot stop doors" + GetNumberText() + "; no doors moving");
559}
560
561void ElevatorDoor::MoveDoors(bool open, bool manual)
562{
563 //opens or closes elevator doors
564
565 //WhichDoors is the doors to move:
566 //1 = both shaft and elevator doors
567 //2 = only elevator doors
568 //3 = only shaft doors
569
570 //ShaftDoorFloor is the floor the shaft doors are on - only has effect if whichdoors is 3
571
572 //this is the parent controller function that runs the movement function for each
573 //individual door component.
574
575 SBS_PROFILE("ElevatorDoor::MoveDoors");
576
577 //find which doors should be moved
578 bool elevdoors = false, shaftdoors = false, playsounds = false;
579 if (WhichDoors == 1)
580 {
581 elevdoors = true;
582 shaftdoors = true;
583 }
584 if (WhichDoors == 2)
585 elevdoors = true;
586 if (WhichDoors == 3)
587 shaftdoors = true;
588
589 if (DoorIsRunning == false || (manual == true && previous_open != open))
590 {
591 //initialization code
592
593 //stop timer
594 timer->Stop();
595
596 DoorIsRunning = true;
597 door_changed = false;
598
600 int index2 = GetManualIndex(ShaftDoorFloor);
601
602 if (ShaftDoorsExist(ShaftDoorFloor) == false && index2 == -1)
603 {
604 if (WhichDoors != 2)
605 {
606 //reset and exit if shaft doors selected for opening
607 OpenDoor = 0;
608 WhichDoors = 0;
609 DoorIsRunning = false;
610 return;
611 }
612 }
613
614 if (manual == false)
615 playsounds = true;
616
617 if (WhichDoors == 3)
618 {
619 //turn on related floor before opening shaft doors
620 if (sbs->InShaft == true || sbs->InElevator == true)
621 {
624 sbs->EnableSkybox(true);
625 sbs->EnableBuildings(true);
626 sbs->EnableLandscape(true);
627 sbs->EnableExternal(true);
628 }
629 }
630 //reset finished states
631 if (elevdoors == true)
633
634 if (shaftdoors == true && index >= 0)
635 {
636 if (ShaftDoors[index])
637 ShaftDoors[index]->ResetFinished();
638 }
639
640 //play direction message sound
641 if (car->MessageOnMove == false)
642 {
643 //play sound when doors start opening
644 if (car->MessageOnStart == true && open == true && car->MessageOnClose == false)
645 car->PlayMessageSound(true);
646
647 //play sound when doors start closing
648 if (car->MessageOnClose == true && open == false)
649 car->PlayMessageSound(true);
650 }
651
652 }
653 else if (previous_open != open && manual == false && door_changed == false)
654 {
655 //if a different direction was specified during movement
656 door_changed = true;
657 playsounds = true;
658 }
659
660 //reset values if power is off
661 if (sbs->GetPower() == false && manual == false)
662 {
663 OpenDoor = 0;
664 WhichDoors = 0;
665 door_changed = false;
666 doors_stopped = false;
667 }
668
669 //play door sounds
670 if (playsounds == true)
671 {
672 if (open == true)
673 {
674 //play elevator opening sound
676 doorsound->Play();
677 }
678 else
679 {
680 //play elevator closing sound
682 doorsound->Play();
683 }
684 car->PlayMessageSound(false);
685 }
686
687 //perform door movement and get open state of each door
688 if (elevdoors == true)
689 Doors->MoveDoors(open, manual);
690
691 if (shaftdoors == true && index >= 0)
692 {
693 if (ShaftDoors[index])
694 ShaftDoors[index]->MoveDoors(open, manual);
695 }
696
697 //update call status (previous_open detects call changes during movement)
698 previous_open = open;
699
700 //wait until all door components are finished moving
701 if (elevdoors == true)
702 {
704 if (Doors->IsFinished() == false)
705 return;
706 }
707 if (shaftdoors == true && index >= 0)
708 {
709 if (ShaftDoors[index])
710 {
711 ShaftDoors[index]->CheckDoorsOpen();
712 if (ShaftDoors[index]->IsFinished() == false)
713 return;
714 }
715 }
716
717 //the doors are open or closed now
718 if (WhichDoors == 3)
719 {
720 //turn off related floor
721
722 if (open == false && (sbs->InShaft == true || sbs->InElevator == true))
723 {
724 if (elev->GetShaft()->ShowFloors == 0)
725 {
728 }
729 else if (elev->GetShaft()->IsShowFloor(ShaftDoorFloor) == false)
730 {
733 }
734 }
735 }
736
737 //reset values
738 OpenDoor = 0;
739 WhichDoors = 0;
740 door_changed = false;
741 doors_stopped = false;
742
743 if (manual == false && open == true)
744 {
745 //reset and enable nudge timer
746 if (elev->FireServicePhase2 == 0)
748
749 //turn on autoclose timer
750 if ((elev->InServiceMode() == false || elev->WaitForDoors == true) &&
751 (elev->UpPeak == false || ShaftDoorFloor != car->GetBottomFloor()) &&
752 (elev->DownPeak == false || ShaftDoorFloor != car->GetTopFloor()))
753 {
754 if (IsSensorBlocked() == false)
755 Reset();
756 else
757 car->Report("not resetting timer for door" + GetNumberText() + " due to blocked sensor");
758 }
759
760 //play late arrival notification if specified
761 if (elev->NotifyLate == true)
763
764 //play direction message sound
765 if (car->MessageOnMove == false && car->MessageOnStart == false && car->MessageOnClose == false)
766 car->PlayMessageSound(true);
767 }
768 else
769 {
770 //turn off nudge timer
771 ResetNudgeTimer(false);
772 }
773
774 //deactivate sensor if doors are closed
775 if (open == false)
776 EnableSensor(false, false);
777
778 DoorIsRunning = false;
779}
780
781DoorWrapper* ElevatorDoor::AddDoors(const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real width, Real height, bool direction, Real tw, Real th)
782{
783 //adds elevator doors specified at a relative central position (off of elevator position)
784 //if direction is false, doors are on the left/right side; otherwise front/back
785 Real x1, x2, x3, x4;
786 Real z1, z2, z3, z4;
787 Real spacing = 0.01; //spacing between doors
788
789 //set up coordinates
790 if (direction == false)
791 {
792 x1 = CenterX;
793 x2 = CenterX;
794 x3 = CenterX;
795 x4 = CenterX;
796 z1 = CenterZ - (width / 2);
797 z2 = CenterZ - spacing;
798 z3 = CenterZ + spacing;
799 z4 = CenterZ + (width / 2);
800 }
801 else
802 {
803 x1 = CenterX - (width / 2);
804 x2 = CenterX - spacing;
805 x3 = CenterX + spacing;
806 x4 = CenterX + (width / 2);
807 z1 = CenterZ;
808 z2 = CenterZ;
809 z3 = CenterZ;
810 z4 = CenterZ;
811 }
812
813 //create left door
814 AddDoorComponent("Left", lefttexture, lefttexture, thickness, "Left", OpenSpeed, OpenSpeed * 0.75, x1, z1, x2, z2, height, 0, tw, th, tw, th);
815
816 //create right door
817 AddDoorComponent("Right", righttexture, righttexture, thickness, "Right", OpenSpeed, OpenSpeed * 0.75, x3, z3, x4, z4, height, 0, tw, th, tw, th);
818
819 //finish doors
820 return FinishDoors();
821}
822
823DoorComponent* ElevatorDoor::AddDoorComponent(DoorWrapper *wrapper, const std::string &name, const std::string &meshname, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
824{
825 //creates a door component - finish with FinishDoor()
826
827 //create door object
828 DoorComponent *door = 0;
829 if (wrapper->IsShaftDoor == false)
830 door = wrapper->CreateDoor(meshname, direction, false, OpenSpeed, CloseSpeed, elev->GetDoorContainer());
831 else
832 door = wrapper->CreateDoor(meshname, direction, false, OpenSpeed, CloseSpeed, elev->GetShaft()->GetShaftDoorContainer());
833
834 if (tw == 0)
835 tw = 1;
836 if (th == 0)
837 th = 1;
838 if (side_tw == 0)
839 side_tw = 1;
840 if (side_th == 0)
841 side_th = 1;
842
844
845 //add main walls
846 sbs->DrawWalls(true, true, false, false, false, false);
847 Wall *wall;
848 wall = door->mesh->CreateWallObject(name);
849 sbs->AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height, height, voffset, voffset, tw, th, false);
850 sbs->ResetWalls();
851
852 //add side walls
853 sbs->DrawWalls(false, false, true, true, true, true);
854 wall = door->mesh->CreateWallObject(name);
855 sbs->AddWallMain(wall, name, sidetexture, thickness, x1, z1, x2, z2, height, height, voffset, voffset, side_tw, side_th, false);
856 sbs->ResetWalls();
857
858 //store extents
859 if (x1 < x2)
860 {
861 door->extents_min.x = x1;
862 door->extents_max.x = x2;
863 }
864 else
865 {
866 door->extents_min.x = x2;
867 door->extents_max.x = x1;
868 }
869 if (z1 < z2)
870 {
871 door->extents_min.z = z1;
872 door->extents_max.z = z2;
873 }
874 else
875 {
876 door->extents_min.z = z2;
877 door->extents_max.z = z1;
878 }
879 door->extents_min.y = voffset;
880 door->extents_max.y = voffset + height;
881
883
884 return door;
885}
886
887DoorWrapper* ElevatorDoor::AddDoorComponent(const std::string &name, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
888{
889 //adds an elevator door component; remake of AddDoors command
890
891 std::string Name, buffer;
892 Name = name;
894 buffer = "ElevatorDoor " + ToString(elev->Number) + ":" + ToString(car->Number) + ":" + ToString(Number) + ":" + Name;
895
896 AddDoorComponent(Doors, name, buffer, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
897 return Doors;
898}
899
900DoorWrapper* ElevatorDoor::AddShaftDoorComponent(int floor, const std::string &name, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
901{
902 //adds a shaft door component; remake of AddShaftDoor command
903
904 //exit if floor is not serviced by the elevator
905 if (!car->IsServicedFloor(floor))
906 return 0;
907
908 int index = car->GetFloorIndex(floor);
909
910 if (index == -1)
911 return 0;
912
913 //create shaft door wrapper if not already created
914 if (!ShaftDoors[index])
915 {
916 if (elev->GetShaft()->GetLevel(floor))
917 ShaftDoors[index] = new DoorWrapper(elev->GetShaft()->GetLevel(floor)->GetMeshObject(), this, true, floor);
918 }
919
920 std::string Name, buffer;
921 Name = name;
923 buffer = "Elevator " + ToString(elev->Number) + ": Shaft Door " + ToString(car->Number) + ":" + ToString(Number) + ":" + ToString(floor) + ":" + Name;
924
925 AddDoorComponent(ShaftDoors[index], name, buffer, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
926 return ShaftDoors[index];
927}
928
929void ElevatorDoor::AddShaftDoorsComponent(const std::string &name, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
930{
931 //adds shaft door components for all serviced floors; remake of AddShaftDoors command
932
933 //create doors
934 for (size_t i = 0; i < car->ServicedFloors.size(); i++)
935 {
936 int floor = car->ServicedFloors[i];
937 AddShaftDoorComponent(floor, name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
938 }
939}
940
941DoorWrapper* ElevatorDoor::FinishDoors(DoorWrapper *wrapper, int floor, bool ShaftDoor, bool DoorWalls, bool TrackWalls)
942{
943 //finishes a door creation
944 //DoorWalls determines if the connection walls (on the sides, and above the doors) should be made
945 //TrackWalls determines if door track connection walls (below and above doors) should be made
946
947 //add floor to manual shaft door list if wrapper doesn't exist and exit
948 if (!wrapper)
949 {
950 if (ShaftDoor == true)
951 ManualFloors.emplace_back(floor);
952 return 0;
953 }
954
955 //exit if no doors exist
956 if (wrapper->doors.empty() == true)
957 {
958 car->ReportError("FinishDoors: no door components have been created");
959 return 0;
960 }
961
962 //get full width and height of doors
963 Real x1 = 0, x2 = 0, y1 = 0, y2 = 0, z1 = 0, z2 = 0;
964 bool firstrun = true;
965 for (size_t i = 0; i < wrapper->doors.size(); i++)
966 {
967 for (int j = 1; j <= 3; j++)
968 {
969 Vector2 extents = wrapper->doors[i]->mesh->GetExtents(j, true);
970 extents.x = sbs->ToLocal(extents.x);
971 extents.y = sbs->ToLocal(extents.y);
972
973 if (j == 1)
974 {
975 if (extents.x < x1 || firstrun == true)
976 x1 = extents.x;
977 if (extents.y > x2 || firstrun == true)
978 x2 = extents.y;
979 }
980 if (j == 2)
981 {
982 if (extents.x < y1 || firstrun == true)
983 y1 = extents.x;
984 if (extents.y > y2 || firstrun == true)
985 y2 = extents.y;
986 }
987 if (j == 3)
988 {
989 if (extents.x < z1 || firstrun == true)
990 z1 = extents.x;
991 if (extents.y > z2 || firstrun == true)
992 z2 = extents.y;
993 firstrun = false;
994 }
995 }
996 }
997
998 if (x2 - x1 > z2 - z1)
999 {
1000 if (ShaftDoor == false)
1001 DoorDirection = true;
1002 wrapper->Width = x2 - x1;
1003 wrapper->Thickness = z2 - z1;
1004 wrapper->Shift = x2 - (wrapper->Width / 2);
1005 }
1006 else
1007 {
1008 if (ShaftDoor == false)
1009 DoorDirection = false;
1010 wrapper->Width = z2 - z1;
1011 wrapper->Thickness = x2 - x1;
1012 wrapper->Shift = z2 - (wrapper->Width / 2);
1013 }
1014 wrapper->Height = y2 - y1;
1015 if (y2 < y1)
1016 wrapper->voffset = y2;
1017 else
1018 wrapper->voffset = y1;
1019
1020 Real base = wrapper->voffset;
1021
1022 if (ShaftDoor == true)
1023 {
1024 //if shaft door, cut walls for door
1025
1026 //create doors
1027 Shaft *shaft = elev->GetShaft();
1028 Floor *floorobj = sbs->GetFloor(floor);
1029 base += floorobj->GetBase(true);
1030
1031 //cut shaft and floor walls
1033 if (DoorDirection == false)
1034 {
1035 if (shaft->GetLevel(floor))
1036 {
1037 if (!shaft->GetLevel(floor)->Cut(false, Vector3(elev->GetPosition().x + x1 - 2, base, elev->GetPosition().z + z1), Vector3(elev->GetPosition().x + x1 + 2, base + Doors->Height, elev->GetPosition().z + z2), true, false, 1))
1038 return 0;
1039 }
1040 floorobj->Cut(Vector3(elev->GetPosition().x + x1 - 2, base, elev->GetPosition().z + z1), Vector3(elev->GetPosition().x + x1 + 2, base + Doors->Height, elev->GetPosition().z + z2), true, false, true, 2);
1041 }
1042 else
1043 {
1044 if (shaft->GetLevel(floor))
1045 {
1046 if (!shaft->GetLevel(floor)->Cut(false, Vector3(elev->GetPosition().x + x1, base, elev->GetPosition().z + z1 - 2), Vector3(elev->GetPosition().x + x2, base + Doors->Height, elev->GetPosition().z + z1 + 2), true, false, 1))
1047 return 0;
1048 }
1049 floorobj->Cut(Vector3(elev->GetPosition().x + x1, base, elev->GetPosition().z + z1 - 2), Vector3(elev->GetPosition().x + x2, base + Doors->Height, elev->GetPosition().z + z1 + 2), true, false, true, 2);
1050 }
1051
1052 //create doorway walls
1053 if (DoorWalls == true)
1054 {
1056 sbs->GetUtility()->AddDoorwayWalls(floorobj->Level, "Connection Walls", "ConnectionWall", 0, 0);
1058 }
1059 }
1060
1061 //create connection track walls
1062 if (TrackWalls == true)
1063 {
1065 std::string name1, name2;
1066
1067 if (ShaftDoor == false)
1068 {
1069 name1 = "Door" + ToString(car->Number) + GetNumberText() + ":F1";
1070 name2 = "Door" + ToString(car->Number) + GetNumberText() + ":F2";
1071 sbs->CreateWallBox(car->Mesh, name1, "Connection", x1, x2, z1, z2, 1, -1.001f + base, 0, 0, false, true, true, true, false);
1072 sbs->CreateWallBox(car->Mesh, name2, "Connection", x1, x2, z1, z2, 1, wrapper->Height + 0.001f + base, 0, 0, false, true, true, true, false);
1073 }
1074 else
1075 {
1076 Shaft *shaft = elev->GetShaft();
1077 MeshObject *mesh = 0;
1078 if (shaft->GetLevel(floor))
1079 mesh = shaft->GetLevel(floor)->GetMeshObject();
1080
1081 Vector3 position (car->GetPosition() - shaft->GetPosition());
1082 name1 = "ShaftDoor" + ToString(elev->Number) + ":" + ToString(car->Number) + ":" + ToString(Number) + ":F1";
1083 name2 = "ShaftDoor" + ToString(elev->Number) + ":" + ToString(car->Number) + ":" + ToString(Number) + ":F2";
1084 sbs->CreateWallBox(mesh, name1, "Connection", position.x + x1, position.x + x2, position.z + z1, position.z + z2, 1, -1.001f + base, 0, 0, false, true, true, true, false);
1085 sbs->CreateWallBox(mesh, name2, "Connection", position.x + x1, position.x + x2, position.z + z1, position.z + z2, 1, wrapper->Height + 0.001f + base, 0, 0, false, true, true, true, false);
1086 }
1087
1089 }
1090
1091 Vector3 center;
1092 center.x = wrapper->GetPosition().x + x1 + ((x2 - x1) / 2);
1093 center.y = wrapper->GetPosition().y + (wrapper->Height / 2);
1094 center.z = wrapper->GetPosition().z + z1 + ((z2 - z1) / 2);
1095
1096 //relocate sound object
1097 if (ShaftDoor == false)
1098 {
1099 doorsound->SetPosition(center);
1100 nudgesound->SetPosition(center);
1101 }
1102 else
1103 {
1104 chime->SetPosition(center);
1105 earlychime->SetPosition(center);
1106 }
1107
1108 //create door sensor
1109 if (GetSensorStatus() == true && ShaftDoor == false && elev->AutoDoors == true)
1110 {
1111 Real sensor_width = sbs->camera->cfg_body_width / 4;
1112 Vector3 min (x1 - sensor_width, wrapper->voffset, z1 - sensor_width);
1113 Vector3 max (x2 + sensor_width, wrapper->voffset + wrapper->Height, z2 + sensor_width);
1114 CreateSensor(min, max);
1115 }
1116
1117 return wrapper;
1118}
1119
1120DoorWrapper* ElevatorDoor::FinishDoors(bool DoorWalls, bool TrackWalls)
1121{
1122 //finish elevator doors
1123
1124 return FinishDoors(Doors, 0, false, DoorWalls, TrackWalls);
1125}
1126
1127DoorWrapper* ElevatorDoor::FinishShaftDoor(int floor, bool DoorWalls, bool TrackWalls)
1128{
1129 //finish shaft door on a specified floor
1130
1131 std::string floornum = ToString(floor);
1132
1133 //exit if floor is not serviced by the elevator
1134 if (!car->IsServicedFloor(floor))
1135 {
1136 car->ReportError("Floor " + floornum + " not a serviced floor");
1137 return 0;
1138 }
1139
1140 if (!sbs->GetFloor(floor))
1141 {
1142 car->ReportError("Floor " + floornum + " does not exist");
1143 return 0;
1144 }
1145
1146 DoorWrapper *wrapper = 0;
1147 int index = car->GetFloorIndex(floor);
1148
1149 if (index > -1)
1150 wrapper = ShaftDoors[index];
1151
1152 return FinishDoors(wrapper, floor, true, DoorWalls, TrackWalls);
1153}
1154
1155bool ElevatorDoor::FinishShaftDoors(bool DoorWalls, bool TrackWalls)
1156{
1157 //finish all shaft doors
1158
1159 for (size_t i = 0; i < car->ServicedFloors.size(); i++)
1160 FinishShaftDoor(car->ServicedFloors[i], DoorWalls, TrackWalls);
1161
1162 return true;
1163}
1164
1165bool ElevatorDoor::AddShaftDoors(const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
1166{
1167 //adds shaft's elevator doors specified at a relative central position (off of elevator origin)
1168 //uses some parameters (width, height, direction) from AddDoor/AddDoors function
1169
1170 //set door parameters
1171 ShaftDoorOrigin = Vector3(CenterX, 0, CenterZ);
1172 ShaftDoorThickness = thickness;
1173
1174 //create doors
1175 for (size_t i = 0; i < car->ServicedFloors.size(); i++)
1176 {
1177 if (!AddShaftDoor(car->ServicedFloors[i], lefttexture, righttexture, ShaftDoorThickness, ShaftDoorOrigin.x, ShaftDoorOrigin.z, voffset, tw, th))
1178 return false;
1179 }
1180
1181 return true;
1182}
1183
1184DoorWrapper* ElevatorDoor::AddShaftDoor(int floor, const std::string &lefttexture, const std::string &righttexture, Real tw, Real th)
1185{
1186 //compatibility version of AddShaftDoor; please use newer implementation instead
1187
1188 return AddShaftDoor(floor, lefttexture, righttexture, ShaftDoorThickness, ShaftDoorOrigin.x, ShaftDoorOrigin.z, 0, tw, th);
1189}
1190
1191DoorWrapper* ElevatorDoor::AddShaftDoor(int floor, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
1192{
1193 //adds a single elevator shaft door, with position and thickness parameters first specified
1194 //by the SetShaftDoors command.
1195 //uses some parameters (width, height, direction) from AddDoor/AddDoors function
1196
1197 //exit if floor is not serviced by the elevator
1198 if (!car->IsServicedFloor(floor))
1199 return 0;
1200
1201 Real x1, x2, x3, x4;
1202 Real z1, z2, z3, z4;
1203 int index = car->GetFloorIndex(floor);
1204
1205 if (index == -1)
1206 return 0;
1207
1208 //set up coordinates
1209 if (DoorDirection == false)
1210 {
1211 x1 = CenterX;
1212 x2 = CenterX;
1213 x3 = CenterX;
1214 x4 = CenterX;
1215 z1 = CenterZ - (Doors->Width / 2);
1216 z2 = CenterZ;
1217 z3 = CenterZ;
1218 z4 = CenterZ + (Doors->Width / 2);
1219 }
1220 else
1221 {
1222 x1 = CenterX - (Doors->Width / 2);
1223 x2 = CenterX;
1224 x3 = CenterX;
1225 x4 = CenterX + (Doors->Width / 2);
1226 z1 = CenterZ;
1227 z2 = CenterZ;
1228 z3 = CenterZ;
1229 z4 = CenterZ;
1230 }
1231
1232 //create doors
1233
1234 //create left door
1235 AddShaftDoorComponent(floor, "Left", lefttexture, lefttexture, thickness, "Left", OpenSpeed, OpenSpeed * 0.75, x1, z1, x2, z2, Doors->Height, voffset, tw, th, tw, th);
1236
1237 //create right door
1238 AddShaftDoorComponent(floor, "Right", righttexture, righttexture, thickness, "Right", OpenSpeed, OpenSpeed * 0.75, x3, z3, x4, z4, Doors->Height, voffset, tw, th, tw, th);
1239
1240 //finish doors
1241 DoorWrapper *wrapper = FinishShaftDoor(floor);
1242
1243 return wrapper;
1244}
1245
1246void ElevatorDoor::SetShaftDoors(Real thickness, Real CenterX, Real CenterZ)
1247{
1248 //notice - this function is deprecated - use newer AddShaftDoor command instead
1249
1250 //pre-set shaft door parameters for the AddShaftDoor command.
1251 //not needed if using the AddShaftDoors command
1252 //the Center values are relative offsets from the associated elevator's center
1253
1254 ShaftDoorThickness = thickness;
1255 ShaftDoorOrigin = Vector3(CenterX, 0, CenterZ);
1256}
1257
1258void ElevatorDoor::ShaftDoorsEnabled(int floor, bool value)
1259{
1260 //turns shaft elevator doors on/off
1261
1262 SBS_PROFILE("ElevatorDoor::ShaftDoorsEnabled");
1263
1264 //exit if shaft's ShowFullShaft is set
1265 if (elev->GetShaft()->GetShowFull() == true && value == false)
1266 return;
1267
1268 //exit if elevator doesn't service the requested floor
1269 int index = GetIndex(floor);
1270
1271 if (index == -1)
1272 return;
1273
1274 //exit if the specified floor has no shaft doors
1275 if (ShaftDoorsExist(floor) == false)
1276 return;
1277
1278 ShaftDoors[index]->Enabled(value);
1279}
1280
1282{
1283 //turn on a range of floors
1284 //if range is 3, show shaft door on current floor (floor), and 1 floor below and above (3 total floors)
1285 //if range is 1, show door on only the current floor (floor)
1286
1287 SBS_PROFILE("ElevatorDoor::ShaftDoorsEnabledRange");
1288
1289 //exit if shaft's ShowFullShaft is set
1290 if (elev->GetShaft()->GetShowFull() == true)
1291 return;
1292
1293 //range must be greater than 0
1294 if (range < 1)
1295 range = 1;
1296
1297 //range must be an odd number; if it's even, then add 1
1298 if (IsEven(range) == true)
1299 range++;
1300
1301 int additionalfloors;
1302 if (range > 1)
1303 additionalfloors = (range - 1) / 2;
1304 else
1305 additionalfloors = 0;
1306
1307 //disable doors 1 floor outside of range
1308 ShaftDoorsEnabled(floor - additionalfloors - 1, false);
1309 ShaftDoorsEnabled(floor + additionalfloors + 1, false);
1310
1311 //enable doors within range
1312 for (int i = floor - additionalfloors; i <= floor + additionalfloors; i++)
1313 ShaftDoorsEnabled(i, true);
1314}
1315
1317{
1318 //returns the internal door state
1319 return Doors->Open;
1320}
1321
1323{
1324 //returns the internal door state
1325 if (ShaftDoorsExist(floor))
1326 {
1327 int index = GetIndex(floor);
1328
1329 if (index > -1)
1330 {
1331 if (ShaftDoors[index])
1332 return ShaftDoors[index]->Open;
1333 }
1334 }
1335 return false;
1336}
1337
1338bool ElevatorDoor::AreShaftDoorsClosed(bool skip_current_floor)
1339{
1340 //returns true if all shaft doors are closed and not moving
1341
1342 if (AreDoorsMoving() == true && skip_current_floor == false)
1343 return false;
1344
1345 for (size_t i = 0; i < ShaftDoors.size(); i++)
1346 {
1347 DoorWrapper* door = ShaftDoors[i];
1348
1349 if (door)
1350 {
1351 if (skip_current_floor == true)
1352 {
1353 //skip elevator's floor if specified
1354 if (door->floor == car->GetFloor())
1355 continue;
1356 }
1357
1358 if (door->Open == true)
1359 return false;
1360 }
1361 }
1362 return true;
1363}
1364
1366{
1367 if (sbs->GetPower() == false)
1368 return;
1369
1370 if (type == 0)
1371 {
1372 //door autoclose timer
1373
1374 //close doors if open
1375 if (door->AreDoorsOpen() == true && (elevator->InServiceMode() == false || elevator->WaitForDoors == true || car->IndependentServiceOnOtherCar() == true))
1376 door->CloseDoors();
1377 }
1378 if (type == 1)
1379 {
1380 //nudge mode timer
1381 door->EnableNudgeMode(true);
1382 }
1383}
1384
1385void ElevatorDoor::Chime(int floor, bool direction)
1386{
1387 if (sbs->GetPower() == false)
1388 return;
1389
1390 //play chime sound on specified floor
1391 if (direction == false && chimesound_loaded != -1)
1392 {
1394 chimesound_loaded = -1;
1395 }
1396 else if (direction == true && chimesound_loaded != 1)
1397 {
1400 }
1401 chime->SetLoopState(false);
1403 chime->Play();
1404}
1405
1406void ElevatorDoor::EarlyChime(int floor, bool direction)
1407{
1408 if (sbs->GetPower() == false)
1409 return;
1410
1411 //play chime sound on specified floor
1412 if (direction == false && earlychimesound_loaded != -1)
1413 {
1414 if (EarlyDownSet == true)
1416 else
1419 }
1420 else if (direction == true && earlychimesound_loaded != 1)
1421 {
1422 if (EarlyUpSet == true)
1424 else
1427 }
1428 earlychime->SetLoopState(false);
1430 earlychime->Play();
1431}
1432
1434{
1435 //reset elevator doors (timer and optionally sensor)
1436
1437 if (elev->AutoDoors == false)
1438 return;
1439
1440 if (sbs->Verbose == true)
1441 {
1442 if (sensor == true)
1443 car->Report("sensor resetting doors" + GetNumberText());
1444 else
1445 car->Report("resetting doors" + GetNumberText());
1446 }
1447
1448 if (quick_close == false)
1449 {
1450 if (DoorTimer > 0)
1451 timer->Start(DoorTimer, true);
1452 }
1453 else
1454 {
1455 if (QuickClose > 0)
1456 timer->Start(QuickClose, true);
1457 }
1458 quick_close = false;
1459
1460 if (sensor == false)
1461 EnableSensor(true, false);
1462}
1463
1465{
1466 //return status of timer
1467 return timer->IsRunning();
1468}
1469
1471{
1472 return doors_stopped;
1473}
1474
1476{
1477 //main loop
1478 SBS_PROFILE("ElevatorDoor::Loop");
1479
1480 if (sbs->GetPower() == false)
1481 nudgesound->Stop();
1482
1483 if (OpenDoor == 1)
1484 MoveDoors(true, false);
1485 if (OpenDoor == -1)
1486 MoveDoors(false, false);
1487 if (OpenDoor == 2)
1488 MoveDoors(true, true);
1489 if (OpenDoor == -2)
1490 MoveDoors(false, true);
1491}
1492
1494{
1495 Doors->Enabled(value);
1496}
1497
1499{
1500 //are doors enabled?
1501 return Doors->IsEnabled;
1502}
1503
1505{
1506 //return value of WhichDoors
1507 return WhichDoors;
1508}
1509
1511{
1512 //returns altitude of the shaft door on the specified floor
1513
1514 int index = GetIndex(floor);
1515
1516 if (index == -1)
1517 return 0;
1518
1519 DoorWrapper *wrapper = ShaftDoors[index];
1520
1521 if (!wrapper)
1522 return 0;
1523
1524 return wrapper->GetPosition().y + wrapper->voffset;
1525}
1526
1527void ElevatorDoor::MoveSound(const Vector3 &position, bool relative_x, bool relative_y, bool relative_z)
1528{
1529 //move sound
1530 Vector3 pos = doorsound->GetPosition();
1531 if (relative_x == false)
1532 pos.x = position.x;
1533 else
1534 pos.x += position.x;
1535 if (relative_y == false)
1536 pos.y = position.y + (Doors->Height / 2);
1537 else
1538 pos.y += position.y;
1539 if (relative_z == false)
1540 pos.z = position.z;
1541 else
1542 pos.z += position.z;
1543 doorsound->SetPosition(pos);
1544 nudgesound->SetPosition(pos);
1545}
1546
1547bool ElevatorDoor::ShaftDoorsExist(int floor, bool include_nonserviced)
1548{
1549 //return true if shaft doors have been created for this door on the specified floor
1550
1551 int index = GetIndex(floor);
1552
1553 if (index != -1)
1554 {
1555 //if shaft doors exist on a serviced floor
1556 if (ShaftDoors[index])
1557 {
1558 if (ShaftDoors[index]->doors.size() > 0)
1559 return true;
1560 }
1561 }
1562 else if (include_nonserviced == true)
1563 {
1564 //if shaft doors exist on a non-serviced floor
1565 for (size_t i = 0; i < ShaftDoors.size(); i++)
1566 {
1567 if (ShaftDoors[i])
1568 {
1569 if (ShaftDoors[i]->floor == floor)
1570 return true;
1571 }
1572 }
1573 }
1574 return false;
1575}
1576
1578{
1579 //return door wrapper object
1580 return Doors;
1581}
1582
1584{
1585 //return shaft door wrapper object for the specified floor
1586
1587 int index = GetIndex(floor);
1588
1589 if (index == -1)
1590 return 0;
1591
1592 return ShaftDoors[index];
1593}
1594
1596{
1597 //return manual array index of the specified floor
1598
1599 for (size_t i = 0; i < ManualFloors.size(); i++)
1600 {
1601 if (ManualFloors[i] == floor)
1602 return (int)i;
1603 }
1604
1605 return -1;
1606}
1607
1609{
1610 //hold door (basically turn off timer)
1611 //disable nudge mode timer if specified
1612
1613 if (sbs->GetPower() == false)
1614 return;
1615
1616 //exit if timer is already stopped
1617 if (timer->IsRunning() == false)
1618 return;
1619
1620 //exit if nudge mode is active
1621 if (GetNudgeStatus() == true)
1622 return;
1623
1624 if (sensor == true)
1625 car->Report("sensor holding doors" + GetNumberText());
1626 else
1627 car->Report("holding doors" + GetNumberText());
1628
1629 timer->Stop();
1630
1631 if (sensor == false)
1632 EnableSensor(false, false);
1633}
1634
1636{
1637 //enable or disable nudge mode
1638
1639 if (sbs->GetPower() == false)
1640 return;
1641
1642 if (value == true && AllowNudgeMode() == true)
1643 {
1644 car->Report("Doors" + GetNumberText() + ": nudge mode activated");
1645 nudge_enabled = true;
1646 if (nudgesound_loaded == false)
1648 nudgesound_loaded = true;
1649 nudgesound->SetLoopState(true);
1650 nudgesound->Play();
1651 CloseDoors();
1652 car->FlashIndicators(true);
1653 }
1654 else if (nudge_enabled == true)
1655 {
1656 car->Report("Doors" + GetNumberText() + ": nudge mode disabled");
1657 nudge_enabled = false;
1658 nudgesound->Stop();
1659 car->FlashIndicators(false);
1660 }
1661}
1662
1664{
1665 //get status of nudge mode
1666
1667 return nudge_enabled;
1668}
1669
1671{
1672 if (sbs->GetPower() == false)
1673 return;
1674
1675 if (GetSensorStatus(false) == true && sensor && (AreDoorsOpen() == true || AreDoorsMoving() == true) && elev->PeakWaiting() == false)
1676 sensor->Loop();
1677}
1678
1680{
1681 //create action for elevator door
1682 std::string action_name1 = "sensor " + ToString(Number);
1683 std::string action_name2 = "sensorreset " + ToString(Number);
1684 std::string full_name1 = car->GetName() + ":" + action_name1;
1685 std::string full_name2 = car->GetName() + ":" + action_name2;
1686
1687 std::vector<Object*> parents;
1688 parents.emplace_back(car);
1689 sensor_action = sbs->AddAction(full_name1, parents, action_name1);
1690 reset_action = sbs->AddAction(full_name2, parents, action_name2);
1691
1692 std::vector<std::string> actions;
1693 actions.emplace_back(full_name2);
1694 actions.emplace_back(full_name1);
1695
1696 //create new trigger
1697 sensor = new Trigger(this, "Sensor", true, SensorSound, area_min, area_max, actions);
1698}
1699
1700bool ElevatorDoor::AreDoorsMoving(int doors, bool car_doors, bool shaft_doors)
1701{
1702 //return true if doors are moving
1703
1704 //if doors is 0, check if doors are moving normally or manually
1705 //if doors is 1, check if doors are moving normally
1706 //if doors is 2, check if doors are moving manually
1707
1708 bool result = false;
1709
1710 if (doors == 0)
1711 result = (OpenDoor != 0);
1712 if (doors == 1)
1713 result = (abs(OpenDoor) == 1);
1714 if (doors == 2)
1715 result = (abs(OpenDoor) == 2);
1716
1717 if (car_doors == true && (WhichDoors == 1 || WhichDoors == 2))
1718 return result;
1719
1720 if (shaft_doors == true && (WhichDoors == 1 || WhichDoors == 3))
1721 return result;
1722
1723 return false;
1724}
1725
1726void ElevatorDoor::EnableSensor(bool value, bool persistent)
1727{
1728 //enable or disable door sensor
1729
1730 //set persistent to false if sensor should be temporarily activated/deactivated only
1731 //and persistent state left untouched
1732
1733 if (sbs->GetPower() == false)
1734 return;
1735
1736 if (value == sensor_enabled)
1737 return;
1738
1739 //if deactivate_only is true, perform operation only is persistent state (sensor_status) is true
1740 if (persistent == false && sensor_status == false)
1741 return;
1742
1743 //only enable sensor if using automatic doors
1744 if (elev->AutoDoors == false)
1745 return;
1746
1747 //if not temporary, change persistent status
1748 if (persistent == true)
1749 {
1750 if (sbs->IsRunning == true || sbs->Verbose)
1751 {
1752 if (value == true)
1753 car->Report("Doors" + GetNumberText() + ": enabling sensor");
1754 else
1755 car->Report("Doors" + GetNumberText() + ": disabling sensor");
1756 }
1757
1758 sensor_status = value;
1759 }
1760
1761 if (sbs->IsRunning == true || sbs->Verbose)
1762 {
1763 if (value == true)
1764 car->Report("Doors" + GetNumberText() + ": activating sensor");
1765 else
1766 car->Report("Doors" + GetNumberText() + ": deactivating sensor");
1767 }
1768
1769 sensor_enabled = value;
1770}
1771
1773{
1774 //get status of door sensor
1775
1776 //if persistent is true, return persistent state (enabled/disabled)
1777 //if persistent is false, return temporary state (activated/deactivated)
1778
1779 if (persistent == false)
1780 return sensor_enabled;
1781
1782 return sensor_status;
1783}
1784
1786{
1787 //return true if sensor is currently blocked/triggered
1788
1789 if (sensor)
1790 return sensor->IsInside();
1791
1792 return false;
1793}
1794
1796{
1797 //returns true if door hold is activated (doors are open and timer has been disabled)
1798 if (AreDoorsOpen() == true && AreDoorsMoving() == false && TimerIsRunning() == false)
1799 return true;
1800
1801 return false;
1802}
1803
1805{
1806 if (sbs->GetPower() == false)
1807 return;
1808
1809 if (AreDoorsOpen() == false || doors_stopped == true)
1810 {
1811 //switch off nudge mode timer if on
1812 if (nudgetimer->IsRunning() == true)
1813 nudgetimer->Stop();
1814
1815 //switch off nudge mode if on
1816 if (GetNudgeStatus() == true)
1817 EnableNudgeMode(false);
1818 }
1819
1820 //turn on nudge mode timer if doors are open
1821 if (start == true)
1822 {
1823 if (AllowNudgeMode() == true && NudgeTimer > 0 && nudgetimer->IsRunning() == false)
1824 nudgetimer->Start(int(NudgeTimer * 1000), true);
1825 }
1826}
1827
1829{
1830 //return true if current situation allows nudge mode to be enabled
1831
1832 //allow nudge mode if fire phase 1 is on (phase 2 is not on Hold) and elevator is not at recall floor
1833 bool firelobby = elev->FireServicePhase1 == 1 && elev->FireServicePhase2 != 2 && elev->OnRecallFloor() == false;
1834
1835 if (GetNudgeStatus() == false && AreDoorsOpen() == true && elev->AutoDoors == true && (elev->InServiceMode() == false || firelobby == true))
1836 {
1837 if ((elev->UpPeak == true && car->GetFloor() == car->GetBottomFloor()) || (elev->DownPeak == true && car->GetFloor() == car->GetTopFloor()))
1838 return false;
1839
1840 return true;
1841 }
1842 return false;
1843}
1844
1846{
1847 //return a text string representing the door number, or blank if it's the only door
1848
1849 std::string doornumber;
1850 if (car->NumDoors > 1)
1851 doornumber = " " + ToString(Number);
1852
1853 return doornumber;
1854}
1855
1857{
1858 //reset door state in case of an internal malfunction
1859
1860 OpenDoor = 0;
1861 WhichDoors = 0;
1862 door_changed = false;
1863 doors_stopped = false;
1864 DoorIsRunning = false;
1865
1866 //first reset timers
1867 timer->Stop();
1868 nudgetimer->Stop();
1869 EnableNudgeMode(false);
1870
1871 Doors->ResetState();
1872
1873 for (size_t i = 0; i < ShaftDoors.size(); i++)
1874 {
1875 if (ShaftDoors[i])
1876 ShaftDoors[i]->ResetState();
1877 }
1878}
1879
1881{
1882 if (door)
1883 {
1884 for (size_t i = 0; i < ShaftDoors.size(); i++)
1885 {
1886 if (ShaftDoors[i] == door)
1887 {
1888 ShaftDoors[i] = 0;
1889 return;
1890 }
1891 }
1892 }
1893}
1894
1896{
1897 return door_changed;
1898}
1899
1901{
1902 return previous_open;
1903}
1904
1906{
1907 for (size_t i = 0; i < ShaftDoors.size(); i++)
1908 {
1909 if (ShaftDoors[i])
1910 {
1911 if (ShaftDoors[i]->floor == floor)
1912 return (int)i;
1913 }
1914 }
1915 return -1;
1916}
1917
1918}
Real cfg_body_width
Definition camera.h:64
bool ReportError(const std::string &message)
void SetDirectionalIndicators(int floor, bool UpLight, bool DownLight)
bool PlayMessageSound(bool type)
Elevator * GetElevator()
bool IndependentServiceOnOtherCar()
std::vector< int > ServicedFloors
Definition elevatorcar.h:38
void NotifyArrival(int floor, bool early=false, int direction=0)
bool IsServicedFloor(int floor, bool report=true)
int GetFloorIndex(int floor)
MeshObject * Mesh
void FlashIndicators(bool value)
void Report(const std::string &message)
void RemoveElevatorDoor(ElevatorDoor *door)
Timer(const std::string &name, ElevatorDoor *parent, ElevatorCar *car, int Type)
DoorComponent * AddDoorComponent(DoorWrapper *wrapper, const std::string &name, const std::string &meshname, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
void ShaftDoorsEnabledRange(int floor, int range)
int GetIndex(int floor)
void CloseDoorsEmergency(int whichdoors=1, int floor=0)
void EnableSensor(bool value, bool persistent=true)
void MoveSound(const Vector3 &position, bool relative_x, bool relative_y, bool relative_z)
DoorWrapper * AddShaftDoor(int floor, const std::string &lefttexture, const std::string &righttexture, Real tw, Real th)
bool FinishShaftDoors(bool DoorWalls=true, bool TrackWalls=true)
DoorWrapper * AddShaftDoorComponent(int floor, const std::string &name, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
std::string OpenSound
std::vector< DoorWrapper * > ShaftDoors
std::string DownChimeSound
DoorWrapper * Doors
ElevatorCar * car
std::string SensorSound
std::string EarlyUpChimeSound
bool GetSensorStatus(bool persistent=true)
std::string UpChimeSound
void ShaftDoorsEnabled(int floor, bool value)
bool AddShaftDoors(const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
bool AreDoorsMoving(int doors=0, bool car_doors=true, bool shaft_doors=true)
Real GetShaftDoorAltitude(int floor)
void CloseDoors(int whichdoors=1, int floor=0, bool manual=false)
std::vector< int > ManualFloors
ElevatorDoor(int number, ElevatorCar *car)
int GetManualIndex(int floor)
void Hold(bool sensor=false)
DoorWrapper * GetDoorWrapper()
bool AreShaftDoorsClosed(bool skip_current_floor=false)
void SetShaftDoors(Real thickness, Real CenterX, Real CenterZ)
void ResetNudgeTimer(bool start=true)
DoorWrapper * FinishDoors(DoorWrapper *wrapper, int floor, bool ShaftDoor, bool DoorWalls=true, bool TrackWalls=true)
void OpenDoorsEmergency(int whichdoors=1, int floor=0)
Vector3 ShaftDoorOrigin
std::string EarlyDownChimeSound
std::string GetNumberText()
void Reset(bool sensor=false)
void RemoveShaftDoor(DoorWrapper *door)
void Enabled(bool value)
void RemoveServicedFloor(int floor)
void AddShaftDoorsComponent(const std::string &name, const std::string &texture, const std::string &sidetexture, Real thickness, const std::string &direction, Real OpenSpeed, Real CloseSpeed, Real x1, Real z1, Real x2, Real z2, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
DoorWrapper * FinishShaftDoor(int floor, bool DoorWalls=true, bool TrackWalls=true)
std::string NudgeSound
std::string CloseSound
void EnableNudgeMode(bool value)
void OpenDoors(int whichdoors=1, int floor=0, bool manual=false)
bool ShaftDoorsExist(int floor, bool include_nonserviced=false)
void Chime(int floor, bool direction)
void EarlyChime(int floor, bool direction)
DoorWrapper * GetShaftDoorWrapper(int floor)
void CreateSensor(Vector3 &area_min, Vector3 &area_max)
void MoveDoors(bool open, bool manual)
void AddServicedFloor(int floor)
bool AreShaftDoorsOpen(int floor)
DoorWrapper * AddDoors(const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real width, Real height, bool direction, Real tw, Real th)
int GetFloorForCar(int car, int number)
bool OnRecallFloor()
bool MoveElevator
Definition elevator.h:45
bool WaitForDoors
Definition elevator.h:94
bool DownPeak
Definition elevator.h:73
bool NotifyLate
Definition elevator.h:97
bool PeakWaiting()
bool Leveling
Definition elevator.h:90
bool InServiceMode()
DynamicMesh * GetDoorContainer()
Definition elevator.h:213
int FireServicePhase2
Definition elevator.h:78
Shaft * GetShaft()
int FireServicePhase1
Definition elevator.h:77
void Cut(const Vector3 &start, const Vector3 &end, bool cutwalls, bool cutfloors, bool fast, int checkwallnumber=0, bool prepare=false)
Definition floor.cpp:607
MeshObject * Level
Definition floor.h:32
Real GetBase(bool relative=false)
Definition floor.cpp:1140
std::string ID
Definition floor.h:38
void EnableGroup(bool value)
Definition floor.cpp:706
void Enabled(bool value)
Definition floor.cpp:377
Wall * CreateWallObject(const std::string &name)
Definition mesh.cpp:208
std::string Name
Definition object.h:52
const std::string & GetName()
Definition object.cpp:53
void SetName(const std::string &name)
Definition object.cpp:72
bool parent_deleting
Definition object.h:64
virtual void SetPositionY(Real value)
Definition object.cpp:313
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:321
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
std::string Type
Definition object.h:135
virtual void SetPosition(const Vector3 &position)
Definition object.cpp:274
Action * AddAction(const std::string &name, std::vector< Object * > &action_parents, const std::string &command, const std::vector< std::string > &parameters)
Definition sbs.cpp:3413
bool GetPower()
Definition sbs.cpp:4701
void EnableBuildings(bool value)
Definition sbs.cpp:1475
bool IsRunning
Definition sbs.h:157
std::string GetConfigString(const std::string &key, const std::string &default_value)
Definition sbs.cpp:3238
bool InShaft
Definition sbs.h:164
Real GetConfigFloat(const std::string &key, Real default_value)
Definition sbs.cpp:3249
bool AddWallMain(Wall *wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height_in1, Real height_in2, Real altitude1, Real altitude2, Real tw, Real th, bool autosize)
Definition sbs.cpp:690
void ResetWalls(bool ToDefaults=false)
Definition sbs.cpp:1854
Floor * GetFloor(int number)
Definition sbs.cpp:1739
Utility * GetUtility()
Definition sbs.cpp:4611
bool FastDelete
Definition sbs.h:188
TextureManager * GetTextureManager()
Definition sbs.cpp:4558
Camera * camera
Definition sbs.h:160
void EnableLandscape(bool value)
Definition sbs.cpp:1482
void EnableSkybox(bool value)
Definition sbs.cpp:1498
Real ToLocal(Real remote_value)
Definition sbs.cpp:2367
bool GetConfigBool(const std::string &key, bool default_value)
Definition sbs.cpp:3243
int GetConfigInt(const std::string &key, int default_value)
Definition sbs.cpp:3232
void EnableExternal(bool value)
Definition sbs.cpp:1489
bool InElevator
Definition sbs.h:163
bool RemoveAction(std::string name)
Definition sbs.cpp:3515
void DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
Definition sbs.cpp:1833
Wall * CreateWallBox(MeshObject *mesh, const std::string &name, const std::string &texture, Real x1, Real x2, Real z1, Real z2, Real height_in, Real voffset, Real tw, Real th, bool inside=true, bool outside=true, bool top=true, bool bottom=true, bool autosize=true)
Definition sbs.cpp:1162
bool Verbose
Definition sbs.h:186
bool Cut(bool relative, const Vector3 &start, const Vector3 &end, bool cutwalls, bool cutfloors, int checkwallnumber=0)
Definition shaft.cpp:930
MeshObject * GetMeshObject()
Definition shaft.cpp:1048
bool GetShowFull()
Definition shaft.h:75
int ShowFloors
Definition shaft.h:44
DynamicMesh * GetShaftDoorContainer()
Definition shaft.h:73
bool IsShowFloor(int floor)
Definition shaft.cpp:347
Level * GetLevel(int floor)
Definition shaft.cpp:135
bool Load(const std::string &filename, bool force=false)
Definition sound.cpp:386
void Stop()
Definition sound.cpp:292
bool Play(bool reset=true)
Definition sound.cpp:321
void SetLoopState(bool value)
Definition sound.cpp:204
void ResetTextureMapping(bool todefaults=false)
Definition texture.cpp:1444
bool IsRunning()
Definition timer.cpp:74
void Start(int milliseconds=-1, bool oneshot=false)
Definition timer.cpp:49
bool IsInside()
Definition trigger.cpp:330
void Loop()
Definition trigger.cpp:267
void ResetDoorwayWalls()
Definition utility.cpp:518
Wall * AddDoorwayWalls(MeshObject *mesh, const std::string &wallname, const std::string &texture, Real tw, Real th)
Definition utility.cpp:529
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
Ogre::Vector2 Vector2
Definition globals.h:59
std::string ToString(int number)
Definition globals.cpp:279
void TrimString(std::string &string)
Definition globals.cpp:188
bool IsEven(int Number)
Definition globals.cpp:37
#define SBS_PROFILE(name)
Definition profiler.h:131
MeshObject * mesh
Definition doorsystem.h:41
void MoveDoors(bool open, bool manual=false)
void Enabled(bool value)
std::vector< DoorComponent * > doors
Definition doorsystem.h:86
DoorComponent * CreateDoor(const std::string &doorname, const std::string &Direction, bool OpenClockwise, Real OpenSpeed, Real CloseSpeed, DynamicMesh *dynmesh)