Skyscraper 2.0
elevatorcar.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Elevator Car 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 "mesh.h"
27#include "polymesh.h"
28#include "primitive.h"
29#include "custom.h"
30#include "floor.h"
31#include "elevator.h"
32#include "elevatordoor.h"
33#include "control.h"
34#include "trigger.h"
35#include "sound.h"
36#include "model.h"
37#include "light.h"
38#include "door.h"
39#include "buttonpanel.h"
40#include "directional.h"
41#include "floorindicator.h"
42#include "shaft.h"
43#include "camera.h"
44#include "dynamicmesh.h"
45#include "texture.h"
46#include "profiler.h"
47#include "cameratexture.h"
48#include "elevatorcar.h"
49#include "manager.h"
50#include "indicator.h"
51#include "timer.h"
52#include "controller.h"
53#include "reverb.h"
54
55#include <time.h>
56
57namespace SBS {
58
60 {
61 public:
63 KeypadTimer(const std::string& name, ElevatorCar* parent) : TimerObject(parent, name)
64 {
65 this->parent = parent;
66 }
67 virtual void Notify();
68 };
69
70
71ElevatorCar::ElevatorCar(Elevator *parent, int number) : Object(parent)
72{
73 //set up SBS object
74 SetValues("ElevatorCar", "", false);
75
76 //init variables
77 Name = "";
78 this->parent = parent;
79 Number = number;
80 carsound = 0;
81 idlesound = 0;
82 alarm = 0;
83 floorbeep = 0;
88 announcesnd = 0;
89 musicsound = 0;
90 DirMessageSound = false;
91 DoorMessageSound = false;
92 Fan = true;
93 MusicPosition = Vector3::ZERO;
94 Height = 0;
95 HeightSet = false;
98 NumDoors = 1;
99 ControlPressActive = false;
100 IsEnabled = true;
101 UpStartSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.UpStartSound", "");
102 DownStartSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.DownStartSound", "");
103 UpMoveSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.UpMoveSound", "");
104 DownMoveSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.DownMoveSound", "");
105 UpStopSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.UpStopSound", "");
106 DownStopSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.DownStopSound", "");
107 IdleSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.IdleSound", "elevidle.wav");
108 AlarmSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.AlarmSound", "bell1.wav");
109 AlarmSoundStop = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.AlarmSoundStop", "bell1-stop.wav");
110 EmergencyStopSound = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.EmergencyStopSound", "");
111 AlarmActive = false;
112 UseFloorBeeps = false;
113 UseFloorSounds = false;
114 UseDirMessageSounds = false;
115 UseDoorMessageSounds = false;
116 MusicUp = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.MusicUp", "");
117 MusicDown = sbs->GetConfigString("Skyscraper.SBS.Elevator.Car.MusicDown", "");
118 MusicOn = sbs->GetConfigBool("Skyscraper.SBS.Elevator.Car.MusicOn", true);
119 MusicOnMove = sbs->GetConfigBool("Skyscraper.SBS.Elevator.Car.MusicOnMove", false);
120 MusicAlwaysOn = sbs->GetConfigBool("Skyscraper.SBS.Elevator.Car.MusicAlwaysOn", false);
121 AutoEnable = sbs->GetConfigBool("Skyscraper.SBS.Elevator.Car.AutoEnable", true);
122 CameraOffset = 0;
123 FirstRun = true;
124 lastcheckresult = false;
125 checkfirstrun = true;
126 lastposition = Vector3::ZERO;
127 lastfloor = 0;
128 lastfloorset = false;
129 StartingFloor = 0;
130 CurrentFloor = 0;
131 Created = false;
132 Offset = 0;
133 GotoFloor = false;
134 LateDirection = 0;
136 MessageOnMove = false;
137 MessageOnStart = false;
138 MessageOnClose = false;
139 indicator = 0;
140 TimerDelay = 2;
141 reverb = 0;
142
143 std::string name = parent->GetName() + ":Car " + ToString(number);
144 SetName(name);
145
146 Mesh = new MeshObject(this, name);
147
148 if (sbs->Verbose)
149 parent->Report("created car " + ToString(number));
150
151 keypad_timer = new KeypadTimer("Input Timeout Timer", this);
152}
153
155{
156 if (sbs->Verbose)
157 parent->Report("deleting objects");
158
159 //delete indicator
160 if (indicator)
161 delete indicator;
162 indicator = 0;
163
164 //delete controls
165 for (size_t i = 0; i < ControlArray.size(); i++)
166 {
167 if (ControlArray[i])
168 {
169 ControlArray[i]->parent_deleting = true;
170 delete ControlArray[i];
171 }
172 ControlArray[i] = 0;
173 }
174
175 //delete triggers
176 for (size_t i = 0; i < TriggerArray.size(); i++)
177 {
178 if (TriggerArray[i])
179 {
180 TriggerArray[i]->parent_deleting = true;
181 delete TriggerArray[i];
182 }
183 TriggerArray[i] = 0;
184 }
185
186 //delete models
187 for (size_t i = 0; i < ModelArray.size(); i++)
188 {
189 if (ModelArray[i])
190 {
191 ModelArray[i]->parent_deleting = true;
192 delete ModelArray[i];
193 }
194 ModelArray[i] = 0;
195 }
196
197 //delete primitives
198 for (size_t i = 0; i < PrimArray.size(); i++)
199 {
200 if (PrimArray[i])
201 {
202 PrimArray[i]->parent_deleting = true;
203 delete PrimArray[i];
204 }
205 PrimArray[i] = 0;
206 }
207
208 //delete custom objects
209 for (size_t i = 0; i < CustomObjectArray.size(); i++)
210 {
211 if (CustomObjectArray[i])
212 {
213 CustomObjectArray[i]->parent_deleting = true;
214 delete CustomObjectArray[i];
215 }
216 CustomObjectArray[i] = 0;
217 }
218
219 //delete lights
220 for (size_t i = 0; i < lights.size(); i++)
221 {
222 if (lights[i])
223 {
224 lights[i]->parent_deleting = true;
225 delete lights[i];
226 }
227 lights[i] = 0;
228 }
229
230 //delete directional indicators
231 if (sbs->Verbose)
232 parent->Report("deleting interior directional indicators");
233
234 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
235 {
236 if (DirIndicatorArray[i])
237 {
238 DirIndicatorArray[i]->parent_deleting = true;
239 delete DirIndicatorArray[i];
240 }
241 DirIndicatorArray[i] = 0;
242 }
243
244 //delete doors
245 if (sbs->Verbose)
246 parent->Report("deleting doors");
247
248 if (DoorArray.size() > 0)
249 {
250 for (size_t i = 0; i < DoorArray.size(); i++)
251 {
252 if (DoorArray[i])
253 {
254 DoorArray[i]->parent_deleting = true;
255 delete DoorArray[i];
256 }
257 DoorArray[i] = 0;
258 }
259 }
260
261 //delete floor indicators
262 if (sbs->Verbose)
263 parent->Report("deleting floor indicators");
264
265 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
266 {
267 if (FloorIndicatorArray[i])
268 {
269 FloorIndicatorArray[i]->parent_deleting = true;
270 delete FloorIndicatorArray[i];
271 }
272 FloorIndicatorArray[i] = 0;
273 }
274
275 //delete panels
276 if (sbs->Verbose)
277 parent->Report("deleting button panels");
278
279 for (size_t i = 0; i < PanelArray.size(); i++)
280 {
281 if (PanelArray[i])
282 {
283 PanelArray[i]->parent_deleting = true;
284 delete PanelArray[i];
285 }
286 PanelArray[i] = 0;
287 }
288
289 //delete doors
290 if (sbs->Verbose)
291 parent->Report("deleting standard doors");
292
293 for (size_t i = 0; i < StdDoorArray.size(); i++)
294 {
295 if (StdDoorArray[i])
296 {
297 StdDoorArray[i]->parent_deleting = true;
298 delete StdDoorArray[i];
299 }
300 StdDoorArray[i] = 0;
301 }
302
303 //delete camera textures
304 for (size_t i = 0; i < CameraTextureArray.size(); i++)
305 {
306 if (CameraTextureArray[i])
307 {
308 CameraTextureArray[i]->parent_deleting = true;
309 delete CameraTextureArray[i];
310 }
311 CameraTextureArray[i] = 0;
312 }
313
314 if (sbs->Verbose)
315 parent->Report("deleting sounds");
316 if (carsound)
317 {
319 delete carsound;
320 }
321 carsound = 0;
322 if (alarm)
323 {
324 alarm->parent_deleting = true;
325 delete alarm;
326 }
327 alarm = 0;
328 if (floorbeep)
329 {
331 delete floorbeep;
332 }
333 floorbeep = 0;
334
335 if (idlesound)
336 {
338 delete idlesound;
339 }
340 idlesound = 0;
341 if (announcesnd)
342 {
344 delete announcesnd;
345 }
346 announcesnd = 0;
347 if (musicsound)
348 {
350 delete musicsound;
351 }
352 musicsound = 0;
353
354 for (size_t i = 0; i < sounds.size(); i++)
355 {
356 if (sounds[i])
357 {
358 sounds[i]->parent_deleting = true;
359 delete sounds[i];
360 }
361 sounds[i] = 0;
362 }
363
364 if (reverb)
365 delete reverb;
366 reverb = 0;
367
368 //delete mesh object
369 if (Mesh)
370 {
371 Mesh->parent_deleting = true;
372 delete Mesh;
373 }
374 Mesh = 0;
375
376 if (sbs->FastDelete == false)
377 {
378 //unregister from parent
379 if (parent_deleting == false)
380 parent->RemoveCar(this);
381 }
382}
383
385{
386 //used with CreateElevator function; this is the car-specific code
387
388 if (Created == true)
389 return ReportError("Has already been created");
390
391 if (parent->Created == false)
392 return ReportError("Elevator has not been created yet");
393
394 StartingFloor = floor;
395
396 if (Number > 1)
397 {
398 Offset = floor - parent->GetCar(Number - 1)->StartingFloor;
399
400 //make sure starting floor is above previous car
402 return ReportError("Car " + ToString(Number) + " must be above car " + ToString(Number - 1));
403 }
404
405 //check if starting floor is valid
407 return ReportError("Floor " + ToString(StartingFloor) + " doesn't exist");
408
409 //make sure starting floor is within associated shaft's range
410 if (StartingFloor < parent->GetShaft()->startfloor || StartingFloor > parent->GetShaft()->endfloor)
411 return ReportError("Invalid starting floor " + ToString(StartingFloor));
412
413 //check door count
414 if (NumDoors < 0)
415 return ReportError("Number of doors invalid");
416
417 //add car's starting floor to serviced floor list
418 //this also ensures that the list is populated to prevent errors
419 if (IsServicedFloor(StartingFloor) == false)
421
422 //ensure that serviced floors are valid for the shaft
423 if (CheckServicedFloors() == false)
424 return false;
425
426 //set starting position
427 if (Number == 1)
428 parent->SetPositionY(sbs->GetFloor(StartingFloor)->GetBase()); //set elevator's position if first car
429 else
430 SetPositionY(sbs->GetFloor(StartingFloor)->GetBase()); //set car's offset if not first car
431
432 //create door objects
433 if (sbs->Verbose)
434 Report("creating doors");
435 if (NumDoors > 0)
436 {
437 for (int i = 1; i <= NumDoors; i++)
438 DoorArray.emplace_back(new ElevatorDoor(i, this));
439 }
440
441 //create sound objects
442 if (sbs->Verbose)
443 Report("creating sound objects");
444 carsound = new Sound(this, "Car", true);
445 idlesound = new Sound(this, "Idle", true);
446 alarm = new Sound(this, "Alarm", true);
447 floorbeep = new Sound(this, "Floor Beep", true);
448 announcesnd = new Sound(this, "Announcement Sound", true);
449 musicsound = new Sound(this, "Music Sound", true);
451
452 //set current floor
454
455 Created = true;
456
457 Report("created on floor " + ToString(StartingFloor));
458 return true;
459}
460
462{
463 return parent;
464}
465
466void ElevatorCar::Report(const std::string &message)
467{
468 //general reporting function
469
470 if (parent->GetCarCount() > 1)
471 parent->Report("Car " + ToString(Number) + ": " + message);
472 else
473 parent->Report(message);
474}
475
476bool ElevatorCar::ReportError(const std::string &message)
477{
478 //general reporting function
479
480 if (parent->GetCarCount() > 1)
481 return parent->ReportError("Car " + ToString(Number) + ": " + message);
482
483 return parent->ReportError(message);
484}
485
486Wall* ElevatorCar::AddWall(const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height1, Real height2, Real voffset1, Real voffset2, Real tw, Real th)
487{
488 //Adds a wall with the specified dimensions
489
490 Wall *wall = Mesh->CreateWallObject(name);
491 sbs->AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height1, height2, voffset1, voffset2, tw, th, true);
492 return wall;
493}
494
495Wall* ElevatorCar::AddFloor(const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real voffset1, Real voffset2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool legacy_behavior)
496{
497 //Adds a floor with the specified dimensions and vertical offset
498
499 Wall *wall = Mesh->CreateWallObject(name);
500 sbs->AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, voffset1, voffset2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
501 return wall;
502}
503
504FloorIndicator* ElevatorCar::AddFloorIndicator(const std::string &texture_prefix, const std::string &blank_texture, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset)
505{
506 //Creates a floor indicator at the specified location
507
508 FloorIndicator* indicator = new FloorIndicator(this, FloorIndicatorArray.size(), parent->Number, Number, texture_prefix, blank_texture, direction, CenterX, CenterZ, width, height, voffset);
509 FloorIndicatorArray.emplace_back(indicator);
510 return indicator;
511}
512
513ButtonPanel* ElevatorCar::CreateButtonPanel(const std::string &texture, int rows, int columns, const std::string &direction, Real CenterX, Real CenterZ, Real buttonwidth, Real buttonheight, Real spacingX, Real spacingY, Real voffset, Real tw, Real th)
514{
515 //create a new button panel object and store the pointer
516
517 int index = (int)PanelArray.size();
518
519 if (sbs->Verbose)
520 Report("creating button panel " + ToString(index + 1));
521
522 ButtonPanel* panel = new ButtonPanel(this, index + 1, texture, rows, columns, direction, CenterX, CenterZ, buttonwidth, buttonheight, spacingX, spacingY, voffset, tw, th);
523 PanelArray.emplace_back(panel);
524 return panel;
525}
526
528{
529 //dump serviced floors list
530
531 //only run if power is enabled
532 if (sbs->GetPower() == false)
533 return;
534
535 if (parent->GetCarCount() == 1)
536 Object::Report("\n--- Elevator " + ToString(parent->Number) + "'s Serviced Floors ---\n");
537 else
538 Object::Report("\n--- Elevator " + ToString(parent->Number) + " Car " + ToString(Number) + "'s Serviced Floors ---\n");
539
540 for (size_t i = 0; i < ServicedFloors.size(); i++)
541 Object::Report(ToString((int)i) + " - " + ToString(ServicedFloors[i]));
542 Object::Report("");
543}
544
545bool ElevatorCar::AddServicedFloor(int number, bool create_shaft_door)
546{
547 //only run if power is enabled
548 if (sbs->GetPower() == false)
549 return false;
550
551 if (sbs->Verbose)
552 Report("adding serviced floor " + ToString(number));
553
554 //check if floor is outside valid floor range
555 if (sbs->IsValidFloor(number) == false)
556 return ReportError("AddServicedFloor: Invalid floor " + ToString(number));
557
558 if (Created == true)
559 {
560 if (CheckServicedFloors() == false)
561 return false;
562 }
563
564 if (IsServicedFloor(number) == false)
565 {
566 //only add floor if not serviced by another car
567 if (parent->IsServicedFloor(number) == false)
568 {
569 ServicedFloors.emplace_back(number);
570 std::sort(ServicedFloors.begin(), ServicedFloors.end());
571
572 //add serviced floors to doors, if needed
573 if (Created == true && create_shaft_door == true)
574 {
575 for (size_t i = 0; i < DoorArray.size(); i++)
576 {
577 DoorArray[i]->AddServicedFloor(number);
578 }
579 }
580 }
581 else
582 return ReportError("AddServicedFloor: Floor " + ToString(number) + " already serviced");
583 }
584
585 return true;
586}
587
588void ElevatorCar::RemoveServicedFloor(int number, bool remove_shaft_door)
589{
590 //only run if power is enabled
591 if (sbs->GetPower() == false)
592 return;
593
594 if (sbs->Verbose)
595 Report("removing serviced floor " + ToString(number));
596
597 int index = GetFloorIndex(number);
598 if (index > -1)
599 ServicedFloors.erase(ServicedFloors.begin() + index);
600
601 //remove serviced floors from doors
602 if (Created == true && remove_shaft_door == true)
603 {
604 for (size_t i = 0; i < DoorArray.size(); i++)
605 {
606 DoorArray[i]->RemoveServicedFloor(number);
607 }
608 }
609}
610
611bool ElevatorCar::IsServicedFloor(int floor, bool report)
612{
613 //returns true if floor is in serviced floor list, otherwise false
614
615 int index = GetFloorIndex(floor);
616 if (index == -1)
617 {
618 if (sbs->Verbose && report == true)
619 Report("Floor " + ToString(floor) + " is not a serviced floor");
620 return false;
621 }
622 else
623 {
624 if (sbs->Verbose && report == true)
625 Report("Floor " + ToString(floor) + " is a serviced floor");
626 return true;
627 }
628}
629
631{
632 //return array index of the specified floor
633
634 for (size_t i = 0; i < ServicedFloors.size(); i++)
635 {
636 if (ServicedFloors[i] == floor)
637 return (int)i;
638 }
639
640 return -1;
641}
642
644{
645 //return number of serviced floors
646 return (int)ServicedFloors.size();
647}
648
650{
651 //get a specific serviced floor
652 if (index >= 0 && index < (int)ServicedFloors.size())
653 return ServicedFloors[index];
654 return 0;
655}
656
658{
659 //ensure serviced floors are valid for the shaft
660
661 for (size_t i = 0; i < ServicedFloors.size(); i++)
662 {
663 if (parent->GetShaft()->IsValidFloor(ServicedFloors[i]) == false)
664 {
665 std::string snum = ToString(parent->AssignedShaft);
666 std::string num = ToString(ServicedFloors[i]);
667 return ReportError("Floor " + num + " not valid for shaft " + snum);
668 }
669 }
670 return true;
671}
672
674{
675 //elevator alarm code
676
677 //only run if power is enabled
678 if (sbs->GetPower() == false)
679 return;
680
681 if (AlarmActive == false)
682 {
683 //ring alarm
684 AlarmActive = true;
685 Report("alarm on");
686 if (AlarmSound != "")
687 {
689 alarm->SetLoopState(true);
690 alarm->Play();
691 }
692 }
693 else if (AlarmActive == true && sbs->camera->MouseDown() == false)
694 {
695 //stop alarm
696 AlarmActive = false;
697 if (AlarmSound != "")
698 {
699 alarm->Stop();
701 alarm->SetLoopState(false);
702 alarm->Play();
703 }
704 Report("alarm off");
705 }
706}
707
709{
710 //Opens the elevator's upper escape hatch, allowing access to the shaft
711
712 Report("opening hatch");
713}
714
716{
717 //startup car initialization
718
719 //exit if not created properly
720 if (Created == false)
721 return;
722
723 //disable objects
724 EnableObjects(false);
725
726 //move car (and possibly elevator) to starting position
728}
729
731{
732 //elevator car monitor loop
733
734 SBS_PROFILE("ElevatorCar::Loop");
735
736 //only run if power is enabled
737 if (sbs->GetPower() == false)
738 {
739 idlesound->Stop();
740 musicsound->Stop();
741 }
742
743 ControlPressActive = false;
744
745 //perform first-run tasks
746 if (FirstRun == true)
747 {
748 FirstRun = false;
749
750 if (parent->OpenOnStart == true)
751 OpenDoors();
752 }
753
754 //play car idle sound if in elevator, or if doors open
755 if (IdleSound != "" && sbs->GetPower() == true)
756 {
757 if (idlesound->IsPlaying() == false && Fan == true)
758 {
759 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving(0, true, false) != 0)
760 {
761 if (sbs->Verbose)
762 Report("playing car idle sound");
763
764 if (idlesound->IsLoaded() == false)
766
767 idlesound->SetLoopState(true);
768 idlesound->Play();
769 }
770 }
771 else
772 {
773 if (Fan == false && idlesound->IsPlaying() == true)
774 {
775 if (sbs->Verbose)
776 Report("stopping car idle sound");
777 idlesound->Stop();
778 }
779 else if (InCar() == false && AreDoorsOpen() == false && AreDoorsMoving() == 0)
780 {
781 if (sbs->Verbose)
782 Report("stopping car idle sound");
783 idlesound->Stop();
784 }
785 }
786 }
787
788 //music processing
789 if ((MusicUp != "" || MusicDown != "") && sbs->GetPower() == true)
790 {
791 if (MusicAlwaysOn == false) //standard mode
792 {
793 //play music sound if in elevator, or if doors open
794 if (musicsound->IsPlaying() == false && MusicOn == true && ((MusicOnMove == true && parent->IsMoving == true) || MusicOnMove == false))
795 {
796 if (parent->InServiceMode() == false)
797 {
798 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving() != 0)
799 {
800 if (sbs->Verbose)
801 Report("playing music");
802
803 int direction = parent->ActiveDirection;
804
805 //load music if not already loaded, or if music direction has changed
806 if (musicsound->IsLoaded() == false || (last_music_direction != direction && MusicOn == true))
807 {
808 if (direction == 0 && last_music_direction != 0)
809 direction = last_music_direction;
810
811 if (direction >= 0)
813 else
815
816 last_music_direction = direction;
817 }
818
820 musicsound->Play(false);
821 }
822 }
823 }
824 else
825 {
826 if ((MusicOn == false || parent->InServiceMode() == true || (MusicOnMove == true && parent->IsMoving == false)) && musicsound->IsPlaying() == true)
827 {
828 if (sbs->Verbose)
829 Report("stopping music");
830 musicsound->Pause();
831 }
832 else if (InCar() == false && AreDoorsOpen() == false && AreDoorsMoving() == 0)
833 {
834 //turn off music if outside elevator car and doors are closed
835 if (sbs->Verbose)
836 Report("stopping music");
837 musicsound->Pause();
838 }
839 else if (MusicOn == true && MusicOnMove == false && musicsound->IsPlaying() == true)
840 {
841 //stop music if elevator changes direction while music is on
843 musicsound->Pause();
844 }
845 }
846 }
847 else if (MusicAlwaysOn == true) //always-on mode
848 {
849 if (musicsound->IsPlaying() == false && MusicOn == true && MusicOnMove == false)
850 {
851 //enable music if in always-on mode
852
853 if (parent->InServiceMode() == false)
854 {
855 if (sbs->Verbose)
856 Report("playing music");
857
858 int direction = parent->ActiveDirection;
859
860 //load music if not already loaded, or if music direction has changed
861 if (musicsound->IsLoaded() == false || (last_music_direction != direction && MusicOn == true))
862 {
863 if (direction == 0 && last_music_direction != 0)
864 direction = last_music_direction;
865
866 if (direction >= 0)
868 else
870
871 last_music_direction = direction;
872 }
873
875 musicsound->SetVolume(0.0);
876 musicsound->Play(false);
877 }
878 }
879 else if (MusicOn == true && MusicOnMove == false && musicsound->IsPlaying() == true)
880 {
882 {
883 //stop music if elevator changes direction while music is on
884 musicsound->Pause();
885 }
886 else
887 {
888 //manage music volume state
889 //(turn on volume only if inside the elevator, or if the doors are open)
890 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving() != 0)
891 musicsound->SetVolume(1.0);
892 else
893 musicsound->SetVolume(0.0);
894 }
895 }
896 }
897 }
898
899 //turn on lights if in elevator, or if doors are open
900 for (size_t i = 0; i < lights.size(); i++)
901 {
902 if (lights[i]->IsEnabled() == false)
903 {
904 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving(0, true, false) != 0)
905 {
906 if (sbs->Verbose)
907 Report("enabling lights");
908
909 lights[i]->Enabled(true);
910 }
911 }
912 else
913 {
914 if (InCar() == false && AreDoorsOpen() == false && AreDoorsMoving() == 0)
915 {
916 if (sbs->Verbose)
917 Report("disabling lights");
918 lights[i]->Enabled(false);
919 }
920 }
921 }
922
923 //process alarm
924 if (AlarmActive == true)
925 Alarm();
926
927 //process door open/close holds
928 if (doorhold_direction > 0)
929 OpenDoors();
930 if (doorhold_direction < 0)
931 CloseDoors();
932
933 //door operations
934 for (int i = 1; i <= NumDoors; i++)
935 {
936 ElevatorDoor *door = GetDoor(i);
937 if (door)
938 door->Loop();
939
940 //reset door timer if peak mode is enabled and a movement is pending
941 if ((parent->UpPeak == true || parent->DownPeak == true))
942 {
943 if ((parent->UpQueue.empty() == false || parent->DownQueue.empty() == false) && (AreDoorsOpen() == true && AreDoorsMoving() == 0))
944 {
945 if (door)
946 {
947 if (door->TimerIsRunning() == false)
948 door->Reset();
949 }
950 }
951 }
952 }
953
954 //run child object runloops
955 if (IsEnabled == true)
956 LoopChildren();
957
958 //process door sensors
959 for (size_t i = 0; i < DoorArray.size(); i++)
960 {
961 if (DoorArray[i])
962 DoorArray[i]->CheckSensor();
963 }
964
965 //process queued sounds
967
968 //reset message sound status
969 DirMessageSound = false;
970 DoorMessageSound = false;
971}
972
973void ElevatorCar::Enabled(bool value)
974{
975 //shows/hides elevator car
976
977 if (IsEnabled == value)
978 return;
979
980 if (sbs->Verbose)
981 {
982 if (value == true)
983 Report("enabling car");
984 else
985 Report("disabling car");
986 }
987
988 Mesh->Enabled(value);
989 EnableDoors(value);
990 IsEnabled = value;
991
992 //floor indicators
993 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
994 {
995 if (FloorIndicatorArray[i])
996 FloorIndicatorArray[i]->Enabled(value);
997 }
998
999 //interior directional indicators
1001
1002 if (value == false)
1003 EnableObjects(false);
1004}
1005
1007{
1008 //enable or disable interior objects, such as floor indicators and button panels
1009
1010 if (AutoEnable == false)
1011 return;
1012
1013 //SBS_PROFILE("ElevatorCar::EnableObjects");
1014 if (sbs->Verbose)
1015 {
1016 if (value == true)
1017 Report("enabling objects");
1018 else
1019 Report("disabling objects");
1020 }
1021
1022 //floor indicators
1023 /*for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
1024 {
1025 if (FloorIndicatorArray[i])
1026 FloorIndicatorArray[i]->Enabled(value);
1027 }*/
1028
1029 //interior directional indicators
1030 //EnableDirectionalIndicators(value);
1031
1032 //controls
1033 for (size_t i = 0; i < ControlArray.size(); i++)
1034 {
1035 if (ControlArray[i])
1036 ControlArray[i]->Enabled(value);
1037 }
1038
1039 //triggers
1040 for (size_t i = 0; i < TriggerArray.size(); i++)
1041 {
1042 if (TriggerArray[i])
1043 TriggerArray[i]->Enabled(value);
1044 }
1045
1046 //models
1047 for (size_t i = 0; i < ModelArray.size(); i++)
1048 {
1049 if (ModelArray[i])
1050 ModelArray[i]->Enabled(value);
1051 }
1052
1053 //panels
1054 for (size_t i = 0; i < PanelArray.size(); i++)
1055 PanelArray[i]->Enabled(value);
1056
1057 //primitives
1058 for (size_t i = 0; i < PrimArray.size(); i++)
1059 {
1060 if (PrimArray[i])
1061 PrimArray[i]->Enabled(value);
1062 }
1063
1064 //custom objects
1065 for (size_t i = 0; i < CustomObjectArray.size(); i++)
1066 {
1067 if (CustomObjectArray[i])
1068 CustomObjectArray[i]->Enabled(value);
1069 }
1070
1071 //sounds
1072 for (size_t i = 0; i < sounds.size(); i++)
1073 {
1074 if (sounds[i])
1075 {
1076 if (sounds[i]->GetLoopState() == true)
1077 {
1078 if (value == false)
1079 sounds[i]->Stop();
1080 else
1081 sounds[i]->Play();
1082 }
1083 }
1084 }
1085
1086 //reverb
1087 if (reverb)
1088 reverb->Enabled(value);
1089}
1090
1092{
1093 //updates all floor indicators
1094
1095 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
1096 {
1097 if (FloorIndicatorArray[i])
1098 FloorIndicatorArray[i]->Update();
1099 }
1100}
1101
1103{
1104 //returns highest serviced floor
1105
1106 if (ServicedFloors.empty() == true)
1107 return 0;
1108
1109 return ServicedFloors[ServicedFloors.size() - 1];
1110}
1111
1113{
1114 //returns lowest serviced floor
1115
1116 if (ServicedFloors.empty() == true)
1117 return 0;
1118
1119 return ServicedFloors[0];
1120}
1121
1122void ElevatorCar::AddDirectionalIndicators(bool relative, bool active_direction, bool single, bool vertical, const std::string &BackTexture, const std::string &uptexture, const std::string &uptexture_lit, const std::string &downtexture, const std::string &downtexture_lit, Real CenterX, Real CenterZ, Real voffset, const std::string &direction, Real BackWidth, Real BackHeight, bool ShowBack, Real tw, Real th)
1123{
1124 //create external directional indicators on all serviced floors
1125
1126 if (sbs->Verbose)
1127 Report("adding directional indicators");
1128
1129 for (size_t i = 0; i < ServicedFloors.size(); i++)
1130 {
1131 if (sbs->GetFloor(ServicedFloors[i]))
1132 sbs->GetFloor(ServicedFloors[i])->AddDirectionalIndicator(parent->Number, Number, relative, active_direction, single, vertical, BackTexture, uptexture, uptexture_lit, downtexture, downtexture_lit, CenterX, CenterZ, voffset, direction, BackWidth, BackHeight, ShowBack, tw, th);
1133 }
1134}
1135
1136DirectionalIndicator* ElevatorCar::AddDirectionalIndicator(bool active_direction, bool single, bool vertical, const std::string &BackTexture, const std::string &uptexture, const std::string &uptexture_lit, const std::string &downtexture, const std::string &downtexture_lit, Real CenterX, Real CenterZ, Real voffset, const std::string &direction, Real BackWidth, Real BackHeight, bool ShowBack, Real tw, Real th)
1137{
1138 //create a directional indicator inside the elevator
1139
1140 if (sbs->Verbose)
1141 Report("adding interior directional indicator");
1142
1143 DirectionalIndicator *indicator = new DirectionalIndicator(this, parent->Number, Number, 0, active_direction, single, vertical, BackTexture, uptexture, uptexture_lit, downtexture, downtexture_lit, CenterX, CenterZ, voffset, direction, BackWidth, BackHeight, ShowBack, tw, th);
1144 DirIndicatorArray.emplace_back(indicator);
1145 return indicator;
1146}
1147
1148void ElevatorCar::SetDirectionalIndicators(int floor, bool UpLight, bool DownLight)
1149{
1150 //set light status of exterior and interior directional indicators
1151 //for interior indicators, the value of floor is passed to the indicator for checks
1152
1153 //exterior indicators
1154 if (sbs->GetFloor(floor))
1155 sbs->GetFloor(floor)->SetDirectionalIndicators(parent->Number, Number, UpLight, DownLight);
1156
1157 //interior indicators
1158 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
1159 {
1161
1162 if (indicator)
1163 {
1164 if (indicator->ActiveDirection == false)
1165 {
1166 indicator->floor = floor;
1167 indicator->DownLight(DownLight);
1168 indicator->UpLight(UpLight);
1169 }
1170 }
1171 }
1172}
1173
1175{
1176 //updates all interior active direction indicators
1177
1178 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
1179 {
1181
1182 if (indicator)
1183 {
1184 if (indicator->ActiveDirection == true)
1185 {
1186 if (parent->ActiveDirection == 1)
1187 {
1188 indicator->DownLight(false);
1189 indicator->UpLight(true);
1190 }
1191 if (parent->ActiveDirection == 0)
1192 {
1193 indicator->DownLight(false);
1194 indicator->UpLight(false);
1195 }
1196 if (parent->ActiveDirection == -1)
1197 {
1198 indicator->DownLight(true);
1199 indicator->UpLight(false);
1200 }
1201 }
1202 }
1203 }
1204}
1205
1207{
1208 //turn on/off all interior directional indicators
1209
1210 if (sbs->Verbose)
1211 {
1212 if (value == true)
1213 Report("enabling interior directional indicators");
1214 else
1215 Report("disabling interior directional indicators");
1216 }
1217
1218 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
1219 {
1220 if (DirIndicatorArray[i])
1221 DirIndicatorArray[i]->Enabled(value);
1222 }
1223}
1224
1226{
1227 //get elevator door object
1228
1229 //return cached check if number is the same
1230 if (lastdoor_number == number && lastdoor_result)
1231 return lastdoor_result;
1232
1233 if (number > 0 && number <= (int)DoorArray.size())
1234 {
1235 if (DoorArray[number - 1])
1236 {
1237 lastdoor_result = DoorArray[number - 1];
1238 lastdoor_number = number;
1239 return lastdoor_result;
1240 }
1241 }
1242 return 0;
1243}
1244
1245bool ElevatorCar::OpenDoorsEmergency(int number, int whichdoors, int floor, bool hold)
1246{
1247 //Simulates manually prying doors open.
1248 //Slowly opens the elevator doors no matter where elevator is.
1249 //If lined up with shaft doors, then opens the shaft doors also
1250
1251 //WhichDoors is the doors to move:
1252 //1 = both shaft and elevator doors
1253 //2 = only elevator doors
1254 //3 = only shaft doors
1255
1256 return OpenDoors(number, whichdoors, floor, true, hold);
1257}
1258
1259void ElevatorCar::CloseDoorsEmergency(int number, int whichdoors, int floor, bool hold)
1260{
1261 //Simulates manually closing doors.
1262 //Slowly closes the elevator doors no matter where elevator is.
1263 //If lined up with shaft doors, then closes the shaft doors also
1264
1265 //WhichDoors is the doors to move:
1266 //1 = both shaft and elevator doors
1267 //2 = only elevator doors
1268 //3 = only shaft doors
1269
1270 CloseDoors(number, whichdoors, floor, true, hold);
1271}
1272
1273bool ElevatorCar::OpenDoors(int number, int whichdoors, int floor, bool manual, bool hold)
1274{
1275 //Opens elevator doors
1276
1277 //if manual is true, then it simulates manually prying doors open,
1278 //Slowly opens the elevator doors no matter where elevator is,
1279 //and if lined up with shaft doors, then opens the shaft doors also.
1280 //if hold is true, sets 'hold' state requiring button to be held to keep doors opening
1281
1282 //WhichDoors is the doors to move:
1283 //1 = both shaft and elevator doors
1284 //2 = only elevator doors
1285 //3 = only shaft doors
1286
1287 //only run if power is enabled
1288 if (sbs->GetPower() == false && manual == false)
1289 return false;
1290
1291 //require open button to be held for fire service phase 2 if not on recall floor
1292 if (FirePhase2Active() == 1 && parent->OnRecallFloor() == false && manual == false)
1293 hold = true;
1294
1295 if (parent->Interlocks == true)
1296 {
1297 //if elevator is moving and interlocks are enabled, stop elevator
1298 if (parent->IsMoving == true && parent->OnFloor == false)
1299 parent->Stop(true);
1300 }
1301
1302 int start = number, end = number;
1303 if (number == 0)
1304 {
1305 start = 1;
1306 end = NumDoors;
1307 }
1308 if (doorhold_direction == 0)
1309 {
1310 if (ControlPressActive == true && parent->AutoDoors == true && parent->InServiceMode() == false && hold == false && manual == false && whichdoors != 3 && DoorsStopped(number) == false)
1311 {
1313
1314 if (AreDoorsOpen(number) == true && AreDoorsMoving(number) == false)
1315 return true; //exit to skip an extra open door call
1316 }
1317
1318 if (hold == true)
1320
1321 if (doorhold_direction > 0)
1322 {
1323 //set persistent values
1324 doorhold_whichdoors = whichdoors;
1325 doorhold_floor = floor;
1326 doorhold_manual = manual;
1327 }
1328
1329 for (int i = start; i <= end; i++)
1330 {
1331 if (GetDoor(i))
1332 GetDoor(i)->OpenDoors(whichdoors, floor, manual);
1333 else
1334 ReportError("Invalid door " + ToString(i));
1335 }
1336 }
1337 else if (doorhold_direction == 1 && sbs->camera->MouseDown() == false)
1338 {
1339 //require button to be held down to open doors
1340
1341 bool closedstate = false;
1342
1343 for (int i = start; i <= end; i++)
1344 {
1345 //check door states first
1346 if (GetDoor(i))
1347 {
1348 if (GetDoor(i)->AreDoorsOpen() == false)
1349 {
1350 closedstate = true;
1351 break;
1352 }
1353 }
1354 else
1355 ReportError("Invalid door " + ToString(i));
1356 }
1357
1358 for (int i = start; i <= end; i++)
1359 {
1360 //close doors using persistent values, if button is released before doors are fully open
1361 if (GetDoor(i))
1362 {
1363 if (closedstate == true)
1365 }
1366 else
1367 ReportError("Invalid door " + ToString(i));
1368 }
1369
1370 //reset persistent values
1373 doorhold_floor = 0;
1374 doorhold_manual = false;
1375 }
1376 else if (doorhold_direction == 2)
1377 {
1378 //hold doors while button is held
1379
1380 if (AreDoorsOpen(number) == true && AreDoorsMoving(number) == false)
1381 {
1382 if (sbs->camera->MouseDown() == true)
1383 {
1384 //hold doors while button is held down
1385 HoldDoors(number);
1386 return true;
1387 }
1388 else
1389 {
1390 //run door open again to reset doors (turn off hold) if button is released
1391 for (int i = start; i <= end; i++)
1392 {
1393 //open doors using persistent values
1394 if (GetDoor(i))
1396 else
1397 ReportError("Invalid door " + ToString(i));
1398 }
1399 }
1400 }
1401
1402 if (sbs->camera->MouseDown() == false)
1403 {
1404 //reset persistent values
1407 doorhold_floor = 0;
1408 doorhold_manual = false;
1409 }
1410 }
1411
1412 return true;
1413}
1414
1415void ElevatorCar::CloseDoors(int number, int whichdoors, int floor, bool manual, bool hold)
1416{
1417 //Closes elevator doors
1418 //if hold is true, sets 'hold' state requiring button to be held to keep doors closing
1419
1420 //WhichDoors is the doors to move:
1421 //1 = both shaft and elevator doors
1422 //2 = only elevator doors
1423 //3 = only shaft doors
1424
1425 //only run if power is enabled
1426 if (sbs->GetPower() == false && manual == false)
1427 return;
1428
1429 //turn on hold option for certain modes
1430 if ((IndependentServiceActive() == true || FirePhase2Active() == 1) && manual == false)
1431 hold = true;
1432
1433 int start = number, end = number;
1434 if (number == 0)
1435 {
1436 start = 1;
1437 end = NumDoors;
1438 }
1439 if (doorhold_direction == 0)
1440 {
1441 for (int i = start; i <= end; i++)
1442 {
1443 if (GetDoor(i))
1444 GetDoor(i)->CloseDoors(whichdoors, floor, manual);
1445 else
1446 ReportError("Invalid door " + ToString(i));
1447 }
1448
1449 if (hold == true)
1450 {
1451 //set persistent values
1452 doorhold_direction = -1;
1453 doorhold_whichdoors = whichdoors;
1454 doorhold_floor = floor;
1455 doorhold_manual = manual;
1456 }
1457 }
1458 else if (doorhold_direction == -1 && sbs->camera->MouseDown() == false)
1459 {
1460 bool openstate = false;
1461 for (int i = start; i <= end; i++)
1462 {
1463 //check door states first
1464 if (GetDoor(i))
1465 {
1466 if (GetDoor(i)->AreDoorsOpen() == true)
1467 {
1468 openstate = true;
1469 break;
1470 }
1471 }
1472 else
1473 ReportError("Invalid door " + ToString(i));
1474 }
1475
1476 if (openstate == true)
1477 {
1478 for (int i = start; i <= end; i++)
1479 {
1480 //open doors using persistent values, if button is released before doors are fully closed
1481 if (GetDoor(i))
1482 {
1483 if (GetDoor(i)->AreDoorsMoving(0) == true)
1485 }
1486 else
1487 ReportError("Invalid door " + ToString(i));
1488 }
1489 }
1490
1491 //reset persistent values
1494 doorhold_floor = 0;
1495 doorhold_manual = false;
1496 }
1497}
1498
1500{
1501 //stops doors that are currently moving; can only be used for manual/emergency movements
1502 //this basically just resets the door internals
1503
1504 int start = number, end = number;
1505 if (number == 0)
1506 {
1507 start = 1;
1508 end = NumDoors;
1509 }
1510 for (int i = start; i <= end; i++)
1511 {
1512 if (GetDoor(i))
1513 GetDoor(i)->StopDoors();
1514 else
1515 ReportError("Invalid door " + ToString(i));
1516 }
1517}
1518
1519DoorWrapper* ElevatorCar::AddDoors(int number, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real width, Real height, bool direction, Real tw, Real th)
1520{
1521 //adds elevator doors specified at a relative central position (off of elevator origin)
1522 //if direction is false, doors are on the left/right side; otherwise front/back
1523
1524 if (GetDoor(number))
1525 return GetDoor(number)->AddDoors(lefttexture, righttexture, thickness, CenterX, CenterZ, width, height, direction, tw, th);
1526 else
1527 ReportError("Invalid door " + ToString(number));
1528 return 0;
1529}
1530
1531bool ElevatorCar::AddShaftDoors(int number, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
1532{
1533 //adds shaft's elevator doors specified at a relative central position (off of elevator origin)
1534 //uses some parameters (width, height, direction) from AddDoors function
1535
1536 if (GetDoor(number))
1537 {
1538 Report("Adding shaft doors...");
1539 return GetDoor(number)->AddShaftDoors(lefttexture, righttexture, thickness, CenterX, CenterZ, voffset, tw, th);
1540 }
1541 else
1542 ReportError("Invalid door " + ToString(number));
1543 return false;
1544}
1545
1546DoorWrapper* ElevatorCar::AddShaftDoor(int floor, int number, const std::string &lefttexture, const std::string &righttexture, Real tw, Real th)
1547{
1548 //adds a single elevator shaft door on the specified floor, with position and thickness parameters first specified
1549 //by the SetShaftDoors command.
1550
1551 if (IsServicedFloor(floor) == true && GetDoor(number))
1552 return GetDoor(number)->AddShaftDoor(floor, lefttexture, righttexture, tw, th);
1553 else
1554 return 0;
1555}
1556
1557DoorWrapper* ElevatorCar::AddShaftDoor(int floor, int number, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
1558{
1559 //adds a single elevator shaft door on the specified floor, with position and thickness parameters first specified
1560 //by the SetShaftDoors command.
1561
1562 if (IsServicedFloor(floor) == true && GetDoor(number))
1563 return GetDoor(number)->AddShaftDoor(floor, lefttexture, righttexture, thickness, CenterX, CenterZ, voffset, tw, th);
1564 else
1565 return 0;
1566}
1567
1568void ElevatorCar::ShaftDoorsEnabled(int number, int floor, bool value)
1569{
1570 //turns shaft elevator doors on/off
1571
1572 SBS_PROFILE("Elevator::ShaftDoorsEnabled");
1573
1574 int start = number, end = number;
1575 if (number == 0)
1576 {
1577 start = 1;
1578 end = NumDoors;
1579 }
1580 for (int i = start; i <= end; i++)
1581 {
1582 ElevatorDoor *door = GetDoor(i);
1583 if (door)
1584 door->ShaftDoorsEnabled(floor, value);
1585 else
1586 ReportError("Invalid door " + ToString(i));
1587 }
1588}
1589
1590void ElevatorCar::ShaftDoorsEnabledRange(int number, int floor, int range)
1591{
1592 //turn on a range of floors
1593 //if range is 3, show shaft door on current floor (floor), and 1 floor below and above (3 total floors)
1594 //if range is 1, show door on only the current floor (floor)
1595
1596 SBS_PROFILE("Elevator::ShaftDoorsEnabledRange");
1597
1598 int start = number, end = number;
1599 if (number == 0)
1600 {
1601 start = 1;
1602 end = NumDoors;
1603 }
1604 for (int i = start; i <= end; i++)
1605 {
1606 ElevatorDoor *door = GetDoor(i);
1607 if (door)
1608 door->ShaftDoorsEnabledRange(floor, range);
1609 else
1610 ReportError("Invalid door " + ToString(i));
1611 }
1612}
1613
1615{
1616 //returns the internal door state
1617
1618 SBS_PROFILE("Elevator::AreDoorsOpen");
1619
1620 int start = number, end = number;
1621 if (number == 0)
1622 {
1623 start = 1;
1624 end = NumDoors;
1625 }
1626 for (int i = start; i <= end; i++)
1627 {
1628 ElevatorDoor *door = GetDoor(i);
1629 if (door)
1630 {
1631 if (door->AreDoorsOpen() == true)
1632 return true;
1633 }
1634 else
1635 ReportError("Invalid door " + ToString(i));
1636 }
1637 return false;
1638}
1639
1640bool ElevatorCar::AreShaftDoorsOpen(int number, int floor)
1641{
1642 //returns the internal shaft door state
1643
1644 SBS_PROFILE("Elevator::AreShaftDoorsOpen");
1645
1646 int start = number, end = number;
1647 if (number == 0)
1648 {
1649 start = 1;
1650 end = NumDoors;
1651 }
1652 for (int i = start; i <= end; i++)
1653 {
1654 ElevatorDoor *door = GetDoor(i);
1655 if (door)
1656 {
1657 if (door->AreShaftDoorsOpen(floor) == true)
1658 return true;
1659 }
1660 else
1661 ReportError("Invalid door " + ToString(i));
1662 }
1663 return false;
1664}
1665
1666bool ElevatorCar::AreShaftDoorsClosed(bool skip_current_floor)
1667{
1668 //return true if all shaft doors are closed and not moving
1669
1670 for (size_t i = 0; i < DoorArray.size(); i++)
1671 {
1672 if (DoorArray[i])
1673 {
1674 if (DoorArray[i]->AreShaftDoorsClosed(skip_current_floor) == false)
1675 return false;
1676 }
1677 }
1678 return true;
1679}
1680
1681void ElevatorCar::Chime(int number, int floor, bool direction, bool early)
1682{
1683 //play chime sound on specified floor
1684
1685 SBS_PROFILE("Elevator::Chime");
1686
1687 //only run if power is enabled
1688 if (sbs->GetPower() == false)
1689 return;
1690
1691 int start = number, end = number;
1692 if (number == 0)
1693 {
1694 start = 1;
1695 end = NumDoors;
1696 }
1697 for (int i = start; i <= end; i++)
1698 {
1699 ElevatorDoor *door = GetDoor(i);
1700 if (door)
1701 {
1702 if (early == false)
1703 door->Chime(floor, direction);
1704 else
1705 door->EarlyChime(floor, direction);
1706 }
1707 else
1708 ReportError("Invalid door " + ToString(i));
1709 }
1710 if (direction == true)
1712 else
1714}
1715
1716void ElevatorCar::ResetDoors(int number, bool sensor)
1717{
1718 //reset elevator door timer
1719
1720 //only run if power is enabled
1721 if (sbs->GetPower() == false)
1722 return;
1723
1724 int start = number, end = number;
1725 if (number == 0)
1726 {
1727 start = 1;
1728 end = NumDoors;
1729 }
1730 for (int i = start; i <= end; i++)
1731 {
1732 ElevatorDoor *door = GetDoor(i);
1733 if (door)
1734 door->Reset(sensor);
1735 else
1736 ReportError("Invalid door " + ToString(i));
1737 }
1738}
1739
1741{
1742 //return true if doors are stopped
1743
1744 int start = number, end = number;
1745 if (number == 0)
1746 {
1747 start = 1;
1748 end = NumDoors;
1749 }
1750 for (int i = start; i <= end; i++)
1751 {
1752 ElevatorDoor *door = GetDoor(i);
1753 if (door)
1754 {
1755 if (door->DoorsStopped() == true)
1756 return true;
1757 }
1758 else
1759 ReportError("Invalid door " + ToString(i));
1760 }
1761 return false;
1762}
1763
1764int ElevatorCar::AreDoorsMoving(int number, bool car_doors, bool shaft_doors)
1765{
1766 //returns 1 if doors are opening (2 manual), -1 if doors are closing (-2 manual), or 0 if doors are not moving
1767 //if the type of door is specified, returns value if that type of door is moving
1768
1769 int start = number, end = number;
1770 if (number == 0)
1771 {
1772 start = 1;
1773 end = NumDoors;
1774 }
1775 for (int i = start; i <= end; i++)
1776 {
1777 ElevatorDoor *door = GetDoor(i);
1778 if (door)
1779 {
1780 if (door->AreDoorsMoving(0, car_doors, shaft_doors) == true)
1781 return door->OpenDoor;
1782 }
1783 else
1784 ReportError("Invalid door " + ToString(i));
1785 }
1786 return 0;
1787}
1788
1789bool ElevatorCar::AreDoorsOpening(int number, bool car_doors, bool shaft_doors)
1790{
1791 //returns true if doors are opening
1792
1793 if (AreDoorsMoving(number, car_doors, shaft_doors) == 1)
1794 return true;
1795 return false;
1796}
1797
1798bool ElevatorCar::AreDoorsClosing(int number, bool car_doors, bool shaft_doors)
1799{
1800 //returns true if doors are closing
1801
1802 if (AreDoorsMoving(number, car_doors, shaft_doors) == -1)
1803 return true;
1804 return false;
1805}
1806
1808{
1809 //enable/disable all doors
1810
1811 SBS_PROFILE("Elevator::EnableDoors");
1812 if (sbs->Verbose)
1813 {
1814 if (value == true)
1815 Report("enabling doors");
1816 else
1817 Report("disabling doors");
1818 }
1819
1820 for (int i = 1; i <= NumDoors; i++)
1821 {
1822 ElevatorDoor *door = GetDoor(i);
1823 if (door)
1824 door->Enabled(value);
1825 }
1826
1827 parent->DoorContainer->Enabled(value);
1828}
1829
1830void ElevatorCar::SetShaftDoors(int number, Real thickness, Real CenterX, Real CenterZ)
1831{
1832 int start = number, end = number;
1833 if (number == 0)
1834 {
1835 start = 1;
1836 end = NumDoors;
1837 }
1838 for (int i = start; i <= end; i++)
1839 {
1840 if (GetDoor(i))
1841 GetDoor(i)->SetShaftDoors(thickness, CenterX, CenterZ);
1842 else
1843 ReportError("Invalid door " + ToString(i));
1844 }
1845}
1846
1847bool ElevatorCar::AddFloorSigns(int door_number, bool relative, const std::string &texture_prefix, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset)
1848{
1849 //adds floor signs at the specified position and direction for each serviced floor,
1850 //depending on if the given door number services the floor or not (unless door_number is 0)
1851
1852 Real x, z;
1853 if (relative == true)
1854 {
1855 x = GetPosition().x + CenterX;
1856 z = GetPosition().z + CenterZ;
1857 }
1858 else
1859 {
1860 x = CenterX;
1861 z = CenterZ;
1862 }
1863
1864 //make sure specified door exists before continuing
1865 if (door_number != 0)
1866 {
1867 if (DoorExists(door_number) == false)
1868 return ReportError("AddFloorSigns: door " + ToString(door_number) + " does not exist");
1869 }
1870
1871 bool autosize_x, autosize_y;
1872 sbs->GetTextureManager()->GetAutoSize(autosize_x, autosize_y);
1873 sbs->GetTextureManager()->SetAutoSize(false, false);
1874
1875 for (size_t i = 0; i < ServicedFloors.size(); i++)
1876 {
1877 bool door_result = false;
1878 int floor = ServicedFloors[i];
1879 Real base = GetDestinationOffset(floor);
1880
1881 if (door_number != 0)
1882 door_result = ShaftDoorsExist(door_number, floor);
1883
1884 if ((door_number == 0 || door_result == true) && sbs->GetFloor(floor))
1885 {
1886 std::string texture = texture_prefix + sbs->GetFloor(floor)->ID;
1887 std::string tmpdirection = direction;
1888 SetCase(tmpdirection, false);
1889
1890 if (tmpdirection == "front" || tmpdirection == "left")
1891 sbs->DrawWalls(true, false, false, false, false, false);
1892 else
1893 sbs->DrawWalls(false, true, false, false, false, false);
1894
1895 if (tmpdirection == "front" || tmpdirection == "back")
1896 sbs->GetFloor(floor)->AddWall("Floor Sign", texture, 0, x - (width / 2), z, x + (width / 2), z, height, height, base + voffset, base + voffset, 1, 1, false);
1897 else
1898 sbs->GetFloor(floor)->AddWall("Floor Sign", texture, 0, x, z - (width / 2), x, z + (width / 2), height, height, base + voffset, base + voffset, 1, 1, false);
1899 sbs->ResetWalls();
1900 }
1901 }
1902 sbs->GetTextureManager()->SetAutoSize(autosize_x, autosize_y);
1903 return true;
1904}
1905
1907{
1908 //check if the specified door exists
1909 //if number is 0, return true if any door exists
1910
1911 int start = number, end = number;
1912 if (number == 0)
1913 {
1914 start = 1;
1915 end = NumDoors;
1916 }
1917 for (int i = start; i <= end; i++)
1918 {
1919 if (GetDoor(i))
1920 return true;
1921 }
1922 return false;
1923}
1924
1925bool ElevatorCar::ShaftDoorsExist(int number, int floor, bool include_nonserviced)
1926{
1927 //return true if shaft doors exist on the specified floor
1928
1929 int start = number, end = number;
1930 if (number == 0)
1931 {
1932 start = 1;
1933 end = NumDoors;
1934 }
1935 for (int i = start; i <= end; i++)
1936 {
1937 ElevatorDoor *door = GetDoor(i);
1938 if (door)
1939 {
1940 if (door->ShaftDoorsExist(floor, include_nonserviced) == true)
1941 return true;
1942 }
1943 }
1944 return false;
1945}
1946
1947Sound* ElevatorCar::AddSound(const std::string &name, const std::string &filename, Vector3 position, bool loop, Real volume, int speed, Real min_distance, Real max_distance, Real doppler_level, Real cone_inside_angle, Real cone_outside_angle, Real cone_outside_volume, Vector3 direction)
1948{
1949 //create a sound object
1950 Sound *sound = new Sound(this, name, false);
1951 sounds.emplace_back(sound);
1952
1953 //set parameters and play sound
1954 sound->Move(position);
1955 sound->SetDirection(direction);
1956 sound->SetVolume(volume);
1957 sound->SetSpeed(speed);
1958 sound->SetDistances(min_distance, max_distance);
1959 sound->SetDirection(direction);
1960 sound->SetDopplerLevel(doppler_level);
1961 sound->SetConeSettings(cone_inside_angle, cone_outside_angle, cone_outside_volume);
1962 sound->Load(filename);
1963 sound->SetLoopState(loop);
1964 if (loop && sbs->IsRunning == true && InCar() == true)
1965 sound->Play();
1966
1967 return sound;
1968}
1969
1971{
1972 //turn off button lights
1973 if (sbs->Verbose)
1974 Report("turning off button lights");
1975
1976 for (size_t i = 0; i < PanelArray.size(); i++)
1977 PanelArray[i]->ChangeAllLights(false);
1978}
1979
1980void ElevatorCar::ChangeLight(int floor, bool value)
1981{
1982 //turn on or off specified button lights
1983
1984 if (value == true)
1985 {
1986 if (sbs->Verbose)
1987 Report("turning on button lights for floor " + ToString(floor));
1988 }
1989 else
1990 {
1991 if (sbs->Verbose)
1992 Report("turning off button lights for floor " + ToString(floor));
1993 }
1994
1995 for (size_t i = 0; i < PanelArray.size(); i++)
1996 PanelArray[i]->ChangeLight(floor, value);
1997}
1998
1999DoorWrapper* ElevatorCar::AddDoorComponent(int number, 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)
2000{
2001 //adds an elevator door component to the specified door at a relative central position (off of elevator origin)
2002
2003 if (GetDoor(number))
2004 return GetDoor(number)->AddDoorComponent(name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
2005 else
2006 ReportError("Invalid door " + ToString(number));
2007 return 0;
2008}
2009
2010DoorWrapper* ElevatorCar::AddShaftDoorComponent(int number, 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)
2011{
2012 //adds a single elevator shaft door component on the specified floor
2013
2014 if (IsServicedFloor(floor) == true && GetDoor(number))
2015 return GetDoor(number)->AddShaftDoorComponent(floor, name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
2016 else
2017 return 0;
2018}
2019
2020void ElevatorCar::AddShaftDoorsComponent(int number, 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)
2021{
2022 //adds shaft's elevator door components specified at a relative central position (off of elevator origin)
2023
2024 if (GetDoor(number))
2025 {
2026 Report("Adding shaft doors component...");
2027 GetDoor(number)->AddShaftDoorsComponent(name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
2028 }
2029 else
2030 ReportError("Invalid door " + ToString(number));
2031}
2032
2033DoorWrapper* ElevatorCar::FinishDoors(int number, bool DoorWalls, bool TrackWalls)
2034{
2035 //finishes elevator door
2036
2037 if (GetDoor(number))
2038 return GetDoor(number)->FinishDoors(DoorWalls, TrackWalls);
2039 else
2040 ReportError("Invalid door " + ToString(number));
2041 return 0;
2042}
2043
2044DoorWrapper* ElevatorCar::FinishShaftDoor(int number, int floor, bool DoorWalls, bool TrackWalls)
2045{
2046 //finishes a single shaft door
2047
2048 if (IsServicedFloor(floor) == true && GetDoor(number))
2049 return GetDoor(number)->FinishShaftDoor(floor, DoorWalls, TrackWalls);
2050 else
2051 return 0;
2052}
2053
2054bool ElevatorCar::FinishShaftDoors(int number, bool DoorWalls, bool TrackWalls)
2055{
2056 //finishes all shaft doors
2057
2058 if (GetDoor(number))
2059 return GetDoor(number)->FinishShaftDoors(DoorWalls, TrackWalls);
2060 else
2061 ReportError("Invalid door " + ToString(number));
2062 return false;
2063}
2064
2066{
2067 //get a button panel object
2068
2069 if (index > (int)PanelArray.size() || index < 1)
2070 return 0;
2071
2072 return PanelArray[index - 1];
2073}
2074
2076{
2077 //get a floor button
2078
2079 if (parent->Running == false)
2080 {
2081 ReportError("Elevator not running");
2082 return 0;
2083 }
2084
2085 if (PanelArray.empty() == false)
2086 {
2087 for (size_t i = 0; i < PanelArray.size(); i++)
2088 {
2089 Control *control = PanelArray[i]->GetFloorButton(floor);
2090 if (control)
2091 return control;
2092 }
2093 }
2094 return 0;
2095}
2096
2097void ElevatorCar::HoldDoors(int number, bool sensor)
2098{
2099 //hold specified door, or all if "0" is given
2100
2101 int start = number, end = number;
2102 if (number == 0)
2103 {
2104 start = 1;
2105 end = NumDoors;
2106 }
2107 for (int i = start; i <= end; i++)
2108 {
2109 if (GetDoor(i))
2110 GetDoor(i)->Hold(sensor);
2111 else
2112 ReportError("Invalid door " + ToString(i));
2113 }
2114}
2115
2116Door* ElevatorCar::AddDoor(std::string name, const std::string &open_sound, const std::string &close_sound, bool open_state, const std::string &texture, const std::string &side_texture, Real thickness, const std::string &face_direction, const std::string &open_direction, bool rotate, Real open_speed, Real close_speed, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
2117{
2118 //interface to the SBS AddDoor function
2119
2120 //set up coordinates
2121 /*Real x1, z1, x2, z2;
2122 if (face_direction == "left" || face_direction == "right")
2123 {
2124 x1 = CenterX;
2125 x2 = CenterX;
2126 z1 = CenterZ - (width / 2);
2127 z2 = CenterZ + (width / 2);
2128 }
2129 else
2130 {
2131 x1 = CenterX - (width / 2);
2132 x2 = CenterX + (width / 2);
2133 z1 = CenterZ;
2134 z2 = CenterZ;
2135 }
2136
2137 //cut area
2138 if (face_direction == "left" || face_direction == "right")
2139 CutAll(Vector3(x1 - 1, GetBase(true) + voffset, z1), Vector3(x2 + 1, GetBase(true) + voffset + height, z2), true, false);
2140 else
2141 CutAll(Vector3(x1, GetBase(true) + voffset, z1 - 1), Vector3(x2, GetBase(true) + voffset + height, z2 + 1), true, false);
2142 */
2143
2144 std::string number = ToString((int)StdDoorArray.size());
2145 if (name == "")
2146 name = "Door " + number;
2147
2148 Door* door = new Door(this, 0, name, open_sound, close_sound, rotate);
2149 door->CreateDoor(open_state, texture, side_texture, thickness, face_direction, open_direction, open_speed, close_speed, CenterX, CenterZ, width, height, voffset, tw, th, side_tw, side_th);
2150 StdDoorArray.emplace_back(door);
2151 return door;
2152}
2153
2154Door* ElevatorCar::CreateDoor(std::string name, const std::string &open_sound, const std::string &close_sound, bool rotate)
2155{
2156 //start creation of a manual door
2157 //since the door is unfinished, AddDoorComponent and FinishDoor need to be run on the returned Door object
2158
2159 std::string number = ToString((int)StdDoorArray.size());
2160 if (name == "")
2161 name = "Door " + number;
2162
2163 Door* door = new Door(this, 0, name, open_sound, close_sound, rotate);
2164 StdDoorArray.emplace_back(door);
2165 return door;
2166}
2167
2169{
2170 //get door object
2171 if (number < (int)StdDoorArray.size())
2172 {
2173 if (StdDoorArray[number])
2174 return StdDoorArray[number];
2175 }
2176
2177 return 0;
2178}
2179
2180Door* ElevatorCar::GetDoor(const std::string &name)
2181{
2182 for (size_t i = 0; i < StdDoorArray.size(); i++)
2183 {
2184 if (StdDoorArray[i]->GetName() == name)
2185 return StdDoorArray[i];
2186 }
2187 return 0;
2188}
2189
2191{
2192 //remove a button panel reference (does not delete the object itself)
2193 for (size_t i = 0; i < PanelArray.size(); i++)
2194 {
2195 if (PanelArray[i] == panel)
2196 {
2197 PanelArray.erase(PanelArray.begin() + i);
2198 return;
2199 }
2200 }
2201}
2202
2204{
2205 //remove a directional indicator reference (does not delete the object itself)
2206 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
2207 {
2208 if (DirIndicatorArray[i] == indicator)
2209 {
2210 DirIndicatorArray.erase(DirIndicatorArray.begin() + i);
2211 return;
2212 }
2213 }
2214}
2215
2217{
2218 //remove an elevator door reference (does not delete the object itself)
2219 for (size_t i = 0; i < DoorArray.size(); i++)
2220 {
2221 if (DoorArray[i] == door)
2222 {
2223 DoorArray.erase(DoorArray.begin() + i);
2224 NumDoors--;
2225
2226 //reset cache values
2227 lastdoor_number = 0;
2228 lastdoor_result = 0;
2229 return;
2230 }
2231 }
2232}
2233
2235{
2236 //remove a floor indicator reference (does not delete the object itself)
2237 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
2238 {
2240 {
2241 FloorIndicatorArray.erase(FloorIndicatorArray.begin() + i);
2242 return;
2243 }
2244 }
2245}
2246
2248{
2249 //remove a door reference (does not delete the object itself)
2250 for (size_t i = 0; i < StdDoorArray.size(); i++)
2251 {
2252 if (StdDoorArray[i] == door)
2253 {
2254 StdDoorArray.erase(StdDoorArray.begin() + i);
2255 return;
2256 }
2257 }
2258}
2259
2261{
2262 //remove a sound reference (does not delete the object itself)
2263 for (size_t i = 0; i < sounds.size(); i++)
2264 {
2265 if (sounds[i] == sound)
2266 {
2267 sounds.erase(sounds.begin() + i);
2268 return;
2269 }
2270 }
2271}
2272
2274{
2275 //remove a light reference (does not delete the object itself)
2276 for (size_t i = 0; i < lights.size(); i++)
2277 {
2278 if (lights[i] == light)
2279 {
2280 lights.erase(lights.begin() + i);
2281 return;
2282 }
2283 }
2284}
2285
2287{
2288 //remove a model reference (does not delete the object itself)
2289 for (size_t i = 0; i < ModelArray.size(); i++)
2290 {
2291 if (ModelArray[i] == model)
2292 {
2293 ModelArray.erase(ModelArray.begin() + i);
2294 return;
2295 }
2296 }
2297}
2298
2300{
2301 //remove a prim reference (does not delete the object itself)
2302 for (size_t i = 0; i < PrimArray.size(); i++)
2303 {
2304 if (PrimArray[i] == prim)
2305 {
2306 PrimArray.erase(PrimArray.begin() + i);
2307 return;
2308 }
2309 }
2310}
2311
2313{
2314 //remove a custom object reference (does not delete the object itself)
2315 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2316 {
2317 if (CustomObjectArray[i] == object)
2318 {
2319 CustomObjectArray.erase(CustomObjectArray.begin() + i);
2320 return;
2321 }
2322 }
2323}
2324
2326{
2327 //remove a control reference (does not delete the object itself)
2328 for (size_t i = 0; i < ControlArray.size(); i++)
2329 {
2330 if (ControlArray[i] == control)
2331 {
2332 ControlArray.erase(ControlArray.begin() + i);
2333 return;
2334 }
2335 }
2336}
2337
2339{
2340 //remove a trigger reference (does not delete the object itself)
2341 for (size_t i = 0; i < TriggerArray.size(); i++)
2342 {
2343 if (TriggerArray[i] == trigger)
2344 {
2345 TriggerArray.erase(TriggerArray.begin() + i);
2346 return;
2347 }
2348 }
2349}
2350
2352{
2353 //checks doors and returns true if any (or the specified door) have nudge mode active
2354
2355 int start = number, end = number;
2356 if (number == 0)
2357 {
2358 start = 1;
2359 end = NumDoors;
2360 }
2361 for (int i = start; i <= end; i++)
2362 {
2363 ElevatorDoor *door = GetDoor(i);
2364 if (door)
2365 {
2366 if (door->GetNudgeStatus() == true)
2367 return true;
2368 }
2369 else
2370 ReportError("Invalid door " + ToString(i));
2371 }
2372
2373 return false;
2374}
2375
2376void ElevatorCar::EnableNudgeMode(bool value, int number)
2377{
2378 //enables nudge mode on all doors or the specified door
2379
2380 //only run if power is enabled
2381 if (sbs->GetPower() == false)
2382 return;
2383
2384 int start = number, end = number;
2385 if (number == 0)
2386 {
2387 start = 1;
2388 end = NumDoors;
2389 }
2390 for (int i = start; i <= end; i++)
2391 {
2392 ElevatorDoor *door = GetDoor(i);
2393 if (door)
2394 door->EnableNudgeMode(value);
2395 else
2396 ReportError("Invalid door " + ToString(i));
2397 }
2398}
2399
2400void ElevatorCar::ResetNudgeTimer(bool start, int number)
2401{
2402 //resets and optionally starts nudge timer on the specified door
2403
2404 int start2 = number, end = number;
2405 if (number == 0)
2406 {
2407 start2 = 1;
2408 end = NumDoors;
2409 }
2410 for (int i = start2; i <= end; i++)
2411 {
2412 ElevatorDoor *door = GetDoor(i);
2413 if (door)
2414 {
2415 door->ResetNudgeTimer(start);
2416 }
2417 else
2418 ReportError("Invalid door " + ToString(i));
2419 }
2420}
2421
2422Light* ElevatorCar::AddLight(const std::string &name, int type)
2423{
2424 //add a global light
2425
2426 Light* light = new Light(this, name, type);
2427 lights.emplace_back(light);
2428 light->Enabled(false);
2429 return light;
2430}
2431
2432Light* ElevatorCar::GetLight(const std::string &name)
2433{
2434 for (size_t i = 0; i < lights.size(); i++)
2435 {
2436 if (lights[i]->GetName() == name)
2437 return lights[i];
2438 }
2439 return 0;
2440}
2441
2442Model* ElevatorCar::AddModel(const std::string &name, const std::string &filename, bool center, Vector3 position, Vector3 rotation, Real max_render_distance, Real scale_multiplier, bool enable_physics, Real restitution, Real friction, Real mass)
2443{
2444 //add a model
2445 Model* model = new Model(this, name, filename, center, position, rotation, max_render_distance, scale_multiplier, enable_physics, restitution, friction, mass);
2446 if (model->load_error == true)
2447 {
2448 delete model;
2449 return 0;
2450 }
2451 ModelArray.emplace_back(model);
2452 return model;
2453}
2454
2456{
2457 //add a model reference
2458
2459 if (!model)
2460 return;
2461
2462 for (size_t i = 0; i < ModelArray.size(); i++)
2463 {
2464 if (ModelArray[i] == model)
2465 return;
2466 }
2467
2468 ModelArray.emplace_back(model);
2469}
2470
2471Primitive* ElevatorCar::AddPrimitive(const std::string &name)
2472{
2473 //add a prim
2474 Primitive* prim = new Primitive(this, name);
2475 PrimArray.emplace_back(prim);
2476 return prim;
2477}
2478
2480{
2481 //add a model reference
2482
2483 if (!primitive)
2484 return;
2485
2486 for (size_t i = 0; i < PrimArray.size(); i++)
2487 {
2488 if (PrimArray[i] == primitive)
2489 return;
2490 }
2491
2492 PrimArray.emplace_back(primitive);
2493}
2494
2495CustomObject* ElevatorCar::AddCustomObject(const std::string &name, const Vector3 &position, const Vector3 &rotation, Real max_render_distance, Real scale_multiplier)
2496{
2497 //add a custom object
2498 CustomObject* object = new CustomObject(this, name, position, rotation, max_render_distance, scale_multiplier);
2499 CustomObjectArray.emplace_back(object);
2500 return object;
2501}
2502
2504{
2505 //add a custom object reference
2506
2507 if (!object)
2508 return;
2509
2510 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2511 {
2512 if (CustomObjectArray[i] == object)
2513 return;
2514 }
2515
2516 CustomObjectArray.emplace_back(object);
2517}
2518
2520{
2521 //add a floor to the display floors list
2522 DisplayFloors.emplace_back(floor);
2523}
2524
2526{
2527 //returns the current floor's indicator display string
2528
2529 //only run if power is enabled
2530 if (sbs->GetPower() == false)
2531 return "";
2532
2533 std::string value;
2534 int floornum = GetFloor();
2535 Floor *floor = sbs->GetFloor(floornum);
2536
2537 if (!floor)
2538 return value;
2539
2540 //only show floor skip text if the floor is not serviced by any car in this elevator
2541 if (parent->UseFloorSkipText == true && IsServicedFloor(floornum) == false && parent->IsServicedFloor(floornum) == false)
2542 value = parent->FloorSkipText;
2543 else
2544 {
2545 if (DisplayFloors.size() > 0)
2546 {
2547 for (size_t i = 0; i < DisplayFloors.size(); i++)
2548 {
2549 if (floornum == DisplayFloors[i])
2550 {
2551 value = floor->ID;
2552 break;
2553 }
2554 }
2555 }
2556 else
2557 value = floor->ID;
2558 }
2559 return value;
2560}
2561
2562Control* ElevatorCar::AddControl(const std::string &name, const std::string &sound, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, int selection_position, std::vector<std::string> &action_names, std::vector<std::string> &textures)
2563{
2564 //add a control
2565 std::vector<Action*> actionnull; //not used
2566 Control* control = new Control(this, name, false, sound, action_names, actionnull, textures, direction, width, height, true, selection_position);
2567 control->Move(Vector3(CenterX, voffset, CenterZ));
2568 ControlArray.emplace_back(control);
2569 return control;
2570}
2571
2572Trigger* ElevatorCar::AddTrigger(const std::string &name, const std::string &sound_file, Vector3 &area_min, Vector3 &area_max, std::vector<std::string> &action_names)
2573{
2574 //add a trigger
2575 Trigger* trigger = new Trigger(this, name, false, sound_file, area_min, area_max, action_names);
2576 TriggerArray.emplace_back(trigger);
2577 return trigger;
2578}
2579
2580bool ElevatorCar::ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
2581{
2582 return Mesh->ReplaceTexture(oldtexture, newtexture);
2583}
2584
2585std::vector<Sound*> ElevatorCar::GetSound(const std::string &name)
2586{
2587 //get sound by name
2588
2589 std::string findname = name;
2590 SetCase(findname, false);
2591 std::vector<Sound*> soundlist;
2592 for (size_t i = 0; i < sounds.size(); i++)
2593 {
2594 if (sounds[i])
2595 {
2596 std::string name2 = sounds[i]->GetName();
2597 SetCase(name2, false);
2598 if (findname == name2)
2599 soundlist.emplace_back(sounds[i]);
2600 }
2601 }
2602 return soundlist;
2603}
2604
2606{
2607 //checks doors and returns true if any (or the specified door) have their door sensor active
2608
2609 int start = number, end = number;
2610 if (number == 0)
2611 {
2612 start = 1;
2613 end = NumDoors;
2614 }
2615 for (int i = start; i <= end; i++)
2616 {
2617 ElevatorDoor *door = GetDoor(i);
2618 if (door)
2619 {
2620 if (door->GetSensorStatus() == true)
2621 return true;
2622 }
2623 else
2624 ReportError("Invalid door " + ToString(i));
2625 }
2626
2627 return false;
2628}
2629
2630void ElevatorCar::EnableSensor(bool value, int number)
2631{
2632 //enables door sensor on all doors or the specified door
2633
2634 //only run if power is enabled
2635 if (sbs->GetPower() == false)
2636 return;
2637
2638 int start = number, end = number;
2639 if (number == 0)
2640 {
2641 start = 1;
2642 end = NumDoors;
2643 }
2644 for (int i = start; i <= end; i++)
2645 {
2646 ElevatorDoor *door = GetDoor(i);
2647 if (door)
2648 door->EnableSensor(value);
2649 else
2650 ReportError("Invalid door " + ToString(i));
2651 }
2652}
2653
2655{
2656 //checks doors and returns true if any (or the specified door) have door hold enabled
2657
2658 int start = number, end = number;
2659 if (number == 0)
2660 {
2661 start = 1;
2662 end = NumDoors;
2663 }
2664 for (int i = start; i <= end; i++)
2665 {
2666 ElevatorDoor *door = GetDoor(i);
2667 if (door)
2668 {
2669 if (door->GetHoldStatus() == true)
2670 return true;
2671 }
2672 else
2673 ReportError("Invalid door " + ToString(i));
2674 }
2675
2676 return false;
2677}
2678
2680{
2681 //reset elevator internal door state, in case of door malfunction
2682
2683 //only run if power is enabled
2684 if (sbs->GetPower() == false)
2685 return;
2686
2687 int start = number, end = number;
2688 if (number == 0)
2689 {
2690 start = 1;
2691 end = NumDoors;
2692 }
2693 for (int i = start; i <= end; i++)
2694 {
2695 ElevatorDoor *door = GetDoor(i);
2696 if (door)
2697 door->ResetState();
2698 else
2699 ReportError("Invalid door " + ToString(i));
2700 }
2701}
2702
2704{
2705 //get a model by name
2706
2707 SetCase(name, false);
2708
2709 for (size_t i = 0; i < ModelArray.size(); i++)
2710 {
2711 if (SetCaseCopy(ModelArray[i]->GetName(), false) == name)
2712 return ModelArray[i];
2713 }
2714
2715 return 0;
2716}
2717
2719{
2720 //get a primitive by name
2721
2722 SetCase(name, false);
2723
2724 for (size_t i = 0; i < PrimArray.size(); i++)
2725 {
2726 if (SetCaseCopy(PrimArray[i]->GetName(), false) == name)
2727 return PrimArray[i];
2728 }
2729
2730 return 0;
2731}
2732
2734{
2735 //get a custom object by name
2736
2737 SetCase(name, false);
2738
2739 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2740 {
2741 if (SetCaseCopy(CustomObjectArray[i]->GetName(), false) == name)
2742 return CustomObjectArray[i];
2743 }
2744
2745 return 0;
2746}
2747
2748void ElevatorCar::SetBeepSound(const std::string &filename)
2749{
2750 //set sound used for floor beeps
2751 if (sbs->Verbose)
2752 Report("setting beep sound");
2753 BeepSound = filename;
2755 UseFloorBeeps = true;
2756}
2757
2758void ElevatorCar::SetFloorSound(const std::string &prefix)
2759{
2760 //set prefix of floor sound
2761 if (sbs->Verbose)
2762 Report("setting floor sound");
2763 FloorSound = prefix;
2765 UseFloorSounds = true;
2766}
2767
2768void ElevatorCar::SetMessageSound(bool type, bool direction, const std::string &filename)
2769{
2770 //if type is true, sets up and down messages. If false, sets open and close messages
2771 //if direction is true, set up message sound; otherwise set down message sound
2772
2773 if (type == true)
2774 {
2775 if (direction == true)
2776 {
2777 if (sbs->Verbose)
2778 Report("setting up message sound");
2779 UpMessageSound = filename;
2781 }
2782 else
2783 {
2784 if (sbs->Verbose)
2785 Report("setting down message sound");
2786 DownMessageSound = filename;
2788 }
2789 UseDirMessageSounds = true;
2790 }
2791 else
2792 {
2793 if (direction == true)
2794 {
2795 if (sbs->Verbose)
2796 Report("setting open message sound");
2797 OpenMessageSound = filename;
2799 }
2800 else
2801 {
2802 if (sbs->Verbose)
2803 Report("setting close message sound");
2804 CloseMessageSound = filename;
2806 }
2807 UseDoorMessageSounds = true;
2808 }
2809}
2810
2812{
2813 //play floor beep sound
2814
2815 //only run if power is enabled
2816 if (sbs->GetPower() == false)
2817 return false;
2818
2819 if (parent->InServiceMode() == true || BeepSound == "" || UseFloorBeeps == false)
2820 return false;
2821
2822 if (sbs->Verbose)
2823 Report("playing floor beep sound");
2824
2825 std::string newsound = BeepSound;
2826 //change the asterisk into the current floor number
2827 ReplaceAll(newsound, "*", ToString(GetFloor()));
2828 TrimString(newsound);
2829 floorbeep->Stop();
2830 floorbeep->Load(newsound);
2831 floorbeep->SetLoopState(false);
2832 floorbeep->Play();
2833 return true;
2834}
2835
2837{
2838 //play floor sound
2839
2840 //only run if power is enabled
2841 if (sbs->GetPower() == false)
2842 return false;
2843
2844 if (parent->InServiceMode() == true || FloorSound == "" || UseFloorSounds == false || parent->SkipFloorSound == true)
2845 return false;
2846
2847 if (sbs->Verbose)
2848 Report("playing floor sound");
2849
2850 std::string newsound = FloorSound;
2851 //change the asterisk into the current floor number
2852 ReplaceAll(newsound, "*", ToString(parent->GotoFloor));
2853 TrimString(newsound);
2854 announcesnd->PlayQueued(newsound, false, false);
2855 return true;
2856}
2857
2859{
2860 //play message sound
2861 //if type is true, play directional up/down sounds, otherwise play door open/close sounds
2862 //if direction is true, play up sound; otherwise play down sound
2863
2864 //only run if power is enabled
2865 if (sbs->GetPower() == false)
2866 return false;
2867
2868 if (parent->InServiceMode() == true)
2869 return false;
2870
2871 if (parent->IsQueueActive() == false && type == true && MessageOnClose == true)
2872 return false;
2873
2874 std::string newsound;
2875
2876 if (type == true)
2877 {
2878 //exit if directional message sounds are off, or one has already been queued
2879 if (UseDirMessageSounds == false || DirMessageSound == true)
2880 return false;
2881
2882 int direction = 0;
2883
2884 if (MessageOnMove == false)
2885 {
2886 if (type == true)
2887 {
2888 if (parent->LastChimeDirection == 0)
2889 return false;
2890
2891 if (parent->NotifyLate == false && parent->NotifyEarly == -1)
2892 return false;
2893 }
2894
2895 direction = parent->LastChimeDirection;
2896
2897 if (parent->LastChimeDirection == 0)
2898 direction = parent->LastQueueDirection;
2899 }
2900 else
2901 direction = parent->ActiveDirection;
2902
2903 if (direction == 1)
2904 {
2905 if (UpMessageSound == "")
2906 return false;
2907
2908 if (sbs->Verbose)
2909 Report("playing up message sound");
2910
2911 newsound = UpMessageSound;
2912 }
2913 else
2914 {
2915 if (DownMessageSound == "")
2916 return false;
2917
2918 if (sbs->Verbose)
2919 Report("playing down message sound");
2920
2921 newsound = DownMessageSound;
2922 }
2923
2924 DirMessageSound = true;
2925 }
2926 else
2927 {
2928 //exit if door message sounds are off, or one has already been queued
2929 if (UseDoorMessageSounds == false || DoorMessageSound == true)
2930 return false;
2931
2932 if (AreDoorsOpening() == true)
2933 {
2934 if (OpenMessageSound == "")
2935 return false;
2936
2937 if (sbs->Verbose)
2938 Report("playing open message sound");
2939
2940 newsound = OpenMessageSound;
2941 }
2942 else if (AreDoorsClosing() == true)
2943 {
2944 if (CloseMessageSound == "")
2945 return false;
2946
2947 if (sbs->Verbose)
2948 Report("playing close message sound");
2949
2950 newsound = CloseMessageSound;
2951 }
2952 else
2953 return false;
2954
2955 DoorMessageSound = true;
2956 }
2957
2958 //change the asterisk into the current floor number
2959 ReplaceAll(newsound, "*", ToString(GetFloor()));
2960 TrimString(newsound);
2961 announcesnd->PlayQueued(newsound, false, false);
2962 return true;
2963}
2964
2966{
2967 //play car starting sounds
2968
2969 carsound->Stop();
2970 if (parent->Direction == 1 && UpStartSound.empty() == false && UpStartSound != "")
2971 {
2972 if (sbs->Verbose)
2973 Report("playing car up start sound");
2974
2976 carsound->SetLoopState(false);
2977 carsound->Play();
2978 }
2979 if (parent->Direction == -1 && DownStartSound.empty() == false && DownStartSound != "")
2980 {
2981 if (sbs->Verbose)
2982 Report("playing car down start sound");
2983
2985 carsound->SetLoopState(false);
2986 carsound->Play();
2987 }
2988}
2989
2991{
2992 //play car stopping sounds
2993 //if emergency is true, plays emergency stop sounds with a fallback to standard sounds
2994
2995 bool play = false;
2996 std::string file;
2997
2998 if (emergency == true)
2999 {
3000 if (EmergencyStopSound.empty() == false && EmergencyStopSound != "")
3001 {
3002 if (sbs->Verbose)
3003 Report("playing car emergency stop sound");
3004
3005 file = EmergencyStopSound;
3006 play = true;
3007 }
3008 }
3009
3010 if (play == false)
3011 {
3012 if (parent->Direction == -1 && UpStopSound.empty() == false && UpStopSound != "")
3013 {
3014 if (sbs->Verbose)
3015 Report("playing car up stop sound");
3016
3017 file = UpStopSound;
3018 play = true;
3019 }
3020 if (parent->Direction == 1 && DownStopSound.empty() == false && DownStopSound != "")
3021 {
3022 if (sbs->Verbose)
3023 Report("playing car down stop sound");
3024
3025 file = DownStopSound;
3026 play = true;
3027 }
3028 }
3029
3030 carsound->Stop();
3031
3032 if (play == true)
3033 {
3034 carsound->Load(file);
3035 carsound->SetLoopState(false);
3036
3037 //set play position to current percent of the total speed
3038 if (parent->AutoAdjustSound == true)
3039 {
3040 if (parent->Direction == 1)
3042 else
3044 }
3045 else
3046 carsound->Reset();
3047
3048 carsound->Play(false);
3049 }
3050}
3051
3053{
3054 //play car movement sounds
3055
3056 if (carsound->IsPlaying() == false)
3057 {
3058 if (parent->Direction == 1 && UpMoveSound.empty() == false && UpMoveSound != "")
3059 {
3060 if (sbs->Verbose)
3061 Report("playing car up movement sound");
3062
3064 carsound->SetLoopState(true);
3065 carsound->Play();
3066 }
3067 else if (parent->Direction == -1 && DownMoveSound.empty() == false && DownMoveSound != "")
3068 {
3069 if (sbs->Verbose)
3070 Report("playing car down movement sound");
3071
3073 carsound->SetLoopState(true);
3074 carsound->Play();
3075 }
3076 }
3077}
3078
3080{
3081 //make sure height value is set
3082 if (HeightSet == false)
3083 {
3084 Height = Mesh->GetHeight();
3085 HeightSet = true;
3086
3087 //position sounds at top of elevator car
3088 Vector3 top = Vector3(0, Height, 0);
3093
3094 //set default music position to elevator height
3095 if (MusicPosition == Vector3(0, 0, 0) && Height > 0)
3096 MusicPosition = top;
3098 }
3099
3100 return Height;
3101}
3102
3103bool ElevatorCar::IsInCar(const Vector3 &position, bool camera)
3104{
3105 //determine if the given 3D position is inside the car
3106
3107 //first checks to see if camera is within an car height range, and then
3108 //checks for a collision with the car floor below
3109
3110 //if camera is true, set associated camera offset
3111
3112 //SBS_PROFILE("ElevatorCar::IsInCar");
3113 bool result = false;
3114
3115 if (IsEnabled == false)
3116 return false;
3117
3118 //if last position is the same as new, return previous result
3119 if (position.positionEquals(lastposition) == true && checkfirstrun == false)
3120 return lastcheckresult;
3121
3122 checkfirstrun = false;
3123
3124 Real ypos = GetPosition().y;
3125
3126 if (position.y >= (ypos - 0.1) && position.y < ypos + (Height * 2))
3127 {
3128 if (Mesh->InBoundingBox(position, false) == true)
3129 {
3130 if (Mesh->HitBeam(position, Vector3::NEGATIVE_UNIT_Y, Height) >= 0)
3131 {
3132 if (camera == true)
3133 CameraOffset = position.y - ypos;
3134 result = true;
3135 }
3136 }
3137 else if (camera == true)
3138 CameraOffset = 0;
3139
3140 if (position.y < ypos + Height)
3141 {
3142 //cache values
3143 lastcheckresult = result;
3144 lastposition = position;
3145
3146 return result;
3147 }
3148 }
3149 else if (camera == true)
3150 CameraOffset = 0;
3151
3152 //cache values
3153 lastcheckresult = false;
3154 lastposition = position;
3155
3156 return false;
3157}
3158
3160{
3161 //check to see if user (camera) is in the car
3162
3163 if (IsEnabled == false)
3164 return false;
3165
3166 //SBS_PROFILE("ElevatorCar::Check");
3167
3168 if (IsInCar(position, true) == true && IsEnabled)
3169 {
3170 if (InCar() == false)
3171 {
3172 //turn on objects if moving into the car
3173 EnableObjects(true);
3175 }
3176 sbs->InElevator = true;
3178 sbs->CarNumber = Number;
3179 sbs->ElevatorSync = true;
3180 return true;
3181 }
3182
3183 //turn off objects if user has moved outside the car
3184 else if (InCar() == true)
3185 {
3186 EnableObjects(false);
3187 }
3188
3189 //if camera is within vertical elevator range, turn on syncing to allow things like elevator surfing
3190 else if (CameraOffset > Height && CameraOffset < Height * 2)
3191 {
3193 sbs->CarNumber = Number;
3194 sbs->ElevatorSync = true;
3195 return true;
3196 }
3197 return false;
3198}
3199
3201{
3202 //stop car sound
3203
3204 carsound->Stop();
3205}
3206
3208{
3209 //Determine floor that the car is on
3210
3211 int newlastfloor;
3212
3213 if (lastfloorset == true)
3214 newlastfloor = sbs->GetFloorNumber(GetPosition().y, lastfloor, true);
3215 else
3216 newlastfloor = sbs->GetFloorNumber(GetPosition().y);
3217
3218 lastfloor = newlastfloor;
3219 lastfloorset = true;
3220 return lastfloor;
3221}
3222
3224{
3225 //returns true if car is on the highest serviced floor
3226
3227 return (GetFloor() == GetTopFloor());
3228}
3229
3231{
3232 //returns true if car is on the lowest serviced floor
3233
3234 return (GetFloor() == GetBottomFloor());
3235}
3236
3238{
3239 //return true if user is currently in car
3240
3241 return (sbs->InElevator == true && sbs->ElevatorNumber == parent->Number && sbs->CarNumber == Number);
3242}
3243
3245{
3246 //return number of closest serviced floor
3247
3248 //only run if power is enabled
3249 if (sbs->GetPower() == false)
3250 return 0;
3251
3252 if (IsServicedFloor(GetFloor()) == true)
3253 return GetFloor();
3254
3255 if (ServicedFloors.size() == 0)
3256 return 0;
3257
3258 bool firstrun = true;
3259 size_t nearest = 0;
3260 Real nearest_difference = 0;
3261
3262 for (size_t i = 0; i < ServicedFloors.size() - 1; i++)
3263 {
3264 if (firstrun == true)
3265 {
3266 if (sbs->GetFloor(ServicedFloors[i]))
3267 {
3268 nearest_difference = std::abs(GetPosition().y - GetDestinationOffset(ServicedFloors[i]));
3269 nearest = i;
3270 firstrun = false;
3271 }
3272 }
3273 else
3274 {
3275 if (sbs->GetFloor(ServicedFloors[i]))
3276 {
3277 Real difference = std::abs(GetPosition().y - GetDestinationOffset(ServicedFloors[i]));
3278 if (difference < nearest_difference)
3279 {
3280 //mark closest
3281 nearest_difference = difference;
3282 nearest = i;
3283 }
3284 }
3285 }
3286 }
3287
3288 return ServicedFloors[nearest];
3289}
3290
3292{
3293 //returns the destination altitude of the specified floor, based on shaft door positioning
3294
3295 if (IsServicedFloor(floor) == false)
3296 return 0.0;
3297
3298 Real result = 0;
3299 bool found = false;
3300 for (size_t i = 0; i < DoorArray.size(); i++)
3301 {
3302 if (DoorArray[i]->ShaftDoorsExist(floor) == true)
3303 {
3304 Real altitude = DoorArray[i]->GetShaftDoorAltitude(floor);
3305
3306 if (altitude > result || found == false)
3307 {
3308 result = altitude;
3309 found = true;
3310 }
3311 }
3312 }
3313
3314 if (found == false)
3315 {
3316 if (sbs->GetFloor(floor))
3317 return sbs->GetFloor(floor)->GetBase();
3318 }
3319 return result;
3320}
3321
3323{
3324 //returns the offset distance from the floor's base altitude the elevator destination is
3325
3326 if (IsServicedFloor(floor) == false)
3327 return 0.0;
3328
3329 if (sbs->GetFloor(floor))
3330 return GetDestinationAltitude(floor) - sbs->GetFloor(floor)->GetBase();
3331
3332 return 0.0;
3333}
3334
3335void ElevatorCar::SetFloor(int floor, bool move_parent)
3336{
3337 //set car's altitude to specified floor
3338
3339 Real altitude = 0;
3340 if (!sbs->GetFloor(floor))
3341 return;
3342
3343 altitude = GetDestinationAltitude(floor);
3344 if (move_parent == true)
3345 {
3346 //move elevator, and any other cars
3347 parent->MoveObjects(altitude - parent->GetPosition().y);
3348 }
3349 else
3350 {
3351 //move just this car
3352 Vector3 vector (0, altitude - GetPosition().y, 0);
3353 Move(vector);
3354 }
3355}
3356
3358{
3359 //return true if car is leveled at a serviced floor
3360
3361 Real tolerance = 0.005;
3362
3363 int floor = GetFloor();
3364 if (IsServicedFloor(floor) == true)
3365 {
3366 Real altitude = GetDestinationAltitude(floor);
3367
3368 if (GetPosition().y >= altitude - tolerance &&
3369 GetPosition().y <= altitude + tolerance)
3370 return true;
3371 }
3372 return false;
3373}
3374
3375bool ElevatorCar::IsOnFloor(int floor, bool leveled)
3376{
3377 //return true if the car is on the specified floor
3378 //if leveled is true, returns true only if the car is leveled on that floor
3379
3380 if (GetFloor() == floor)
3381 {
3382 if (leveled == false)
3383 return true;
3384 else if (IsLeveled() == true && parent->IsMoving == false)
3385 return true;
3386 }
3387
3388 return false;
3389}
3390
3391void ElevatorCar::NotifyArrival(int floor, bool early, int direction)
3392{
3393 //notify on car arrival (play chime and turn on related directional indicator lantern)
3394
3395 //only run if power is enabled
3396 if (sbs->GetPower() == false)
3397 return;
3398
3399 //do not notify if in a service mode
3400 if (parent->InServiceMode() == true)
3401 return;
3402
3403 //get call button status
3404 bool up = true, down = true;
3405
3406 //if ChimeOnArrival is off, only chime if responding to a hall call
3407 if (parent->ChimeOnArrival == false && direction == 0)
3408 {
3409 //get call status from controller
3410 parent->GetCallStatus(floor, up, down);
3411
3412 //in DD mode, set direction to be the call response direction
3413 if (parent->GetDestinationDispatch() == true)
3414 direction = RespondingToCall(floor);
3415 }
3416
3417 bool new_direction = false;
3418
3419 //get notification direction
3420 if (LateDirection != 0)
3421 {
3422 //notify is a late notification
3423 if (LateDirection == 1)
3424 new_direction = true;
3425 else
3426 new_direction = false;
3427 LateDirection = 0;
3428 }
3429 else
3430 {
3431 if (direction == 0)
3432 {
3433 //notify is for a standard arrival
3434 new_direction = parent->GetArrivalDirection(floor);
3435 }
3436 else
3437 {
3438 //notify is for a same-floor call
3439 if (direction == 1)
3440 new_direction = true;
3441 else
3442 new_direction = false;
3443 }
3444 }
3445
3446 //play chime sound and change indicator
3447 if (new_direction == true)
3448 {
3449 if (up == true || direction == 1 || parent->NotifyLate == true || (parent->GetDestinationDispatch() == true && parent->ChimeOnArrival == true))
3450 {
3451 Chime(0, floor, true, early);
3452 SetDirectionalIndicators(floor, true, false);
3453 }
3455 }
3456 else
3457 {
3458 if (down == true || direction == -1 || parent->NotifyLate == true || (parent->GetDestinationDispatch() == true && parent->ChimeOnArrival == true))
3459 {
3460 Chime(0, floor, false, early);
3461 SetDirectionalIndicators(floor, false, true);
3462 }
3464 }
3465
3466 //play floor sound
3467 if (parent->FireServicePhase1 == 0 && parent->FireServicePhase2 == 0 && direction == 0)
3469}
3470
3472{
3473 //returns true if independent service mode is active for this car
3474
3476}
3477
3479{
3480 //returns true if independent service mode is active on this elevator, but for a different car
3481
3483}
3484
3486{
3487 //returns value if fire phase 2 mode is active for this car
3488
3490 return parent->FireServicePhase2;
3491 return 0;
3492}
3493
3495{
3496 //returns true if fire phase 2 mode is active on this elevator, but for a different car
3497
3499}
3500
3501void ElevatorCar::SetControls(const std::string &action_name)
3502{
3503 for (size_t i = 0; i < PanelArray.size(); i++)
3504 {
3505 PanelArray[i]->SetControls(action_name);
3506 }
3507}
3508
3510{
3511 //flash all floor indicators if supported
3512
3513 //only run if power is enabled
3514 if (sbs->GetPower() == false)
3515 return;
3516
3517 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
3518 FloorIndicatorArray[i]->Flash(value);
3519}
3520
3521CameraTexture* ElevatorCar::AddCameraTexture(const std::string &name, int quality, Real fov, const Vector3 &position, bool use_rotation, const Vector3 &rotation)
3522{
3523 //add a camera texture
3524 CameraTexture* cameratexture = new CameraTexture(this, name, quality, fov, position, use_rotation, rotation);
3525 CameraTextureArray.emplace_back(cameratexture);
3526 return cameratexture;
3527}
3528
3530{
3531 //remove a cameratexture reference (does not delete the object itself)
3532 for (size_t i = 0; i < CameraTextureArray.size(); i++)
3533 {
3534 if (CameraTextureArray[i] == camtex)
3535 {
3536 CameraTextureArray.erase(CameraTextureArray.begin() + i);
3537 return;
3538 }
3539 }
3540}
3541
3542bool ElevatorCar::RespondingToCall(int floor, int direction)
3543{
3544 //returns true if the car is responding to a call on the specified floor
3545
3546 Elevator *e = GetElevator();
3547
3548 //if proceeding to call floor for a call
3549 if (GotoFloor == true && e->GotoFloor == floor && e->GetActiveCallFloor() == e->GotoFloor)
3550 {
3551 //and if a hall call, with the same call direction
3552 if (e->GetActiveCallType() == 1 && e->GetActiveCallDirection() == direction)
3553 return true;
3554 }
3555
3556 return false;
3557}
3558
3560{
3561 //same as other function, but returns the direction of the call
3562
3563 Elevator *e = GetElevator();
3564
3565 //if proceeding to call floor for a call
3566 if (GotoFloor == true && e->GotoFloor == floor && e->GetActiveCallFloor() == e->GotoFloor)
3567 {
3568 //and if a hall call, with the same call direction
3569 if (e->GetActiveCallType() == 1)
3570 return e->GetActiveCallDirection();
3571 }
3572
3573 return 0;
3574}
3575
3576Indicator* ElevatorCar::AddKeypadIndicator(const std::string& sound, const std::string& texture_prefix, const std::string& blank_texture, const std::string& direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, Real timer_duration)
3577{
3578 if (indicator)
3579 return 0;
3580
3581 indicator = new Indicator(this, sound, texture_prefix, blank_texture, direction, CenterX, CenterZ, width, height, voffset, timer_duration);
3582
3583 return indicator;
3584}
3585
3586void ElevatorCar::UpdateKeypadIndicator(const std::string& text, bool play_sound)
3587{
3588 if (indicator)
3589 indicator->Update(text, play_sound);
3590}
3591
3593{
3594 //report which elevator is assigned, on indicator
3595 std::string message = "Requested";
3596
3597 Elevator* e = GetElevator();
3598
3599 //show an error if a floor hasn't been selected due to different factors
3600 if (e->InspectionService == true)
3601 KeypadError();
3602 else if (e->FireServicePhase1 == 1 && e->FireServicePhase2 == 0)
3603 KeypadError();
3604 else if (e->Running == false)
3605 KeypadError();
3606 else if (e->IndependentService == true && (AreDoorsOpen() == false || AreDoorsMoving() != 0))
3607 KeypadError();
3608 else if (e->FireServicePhase2 == 2)
3609 KeypadError();
3610 else if (e->LimitQueue == true && ((e->QueuePositionDirection == 1 && floor < GetFloor() && e->UpQueue.empty() == false) || (e->QueuePositionDirection == -1 && floor > GetFloor() && e->DownQueue.empty() == false)))
3611 KeypadError();
3612 else if (e->LimitQueue == true && e->IsMoving == true && floor == GetFloor())
3613 KeypadError();
3614 else if (GetFloorIndex(floor) == -1)
3615 KeypadError();
3616 else
3617 UpdateKeypadIndicator(message);
3618}
3619
3620bool ElevatorCar::Input(const std::string& text)
3621{
3622 //input a keypad character
3623
3624 //only run if power is enabled
3625 if (sbs->GetPower() == false)
3626 return false;
3627
3628 //only allow single characters
3629 if (text.length() != 1)
3630 return false;
3631
3632 //check lock state
3633 //if (IsLocked() == true)
3634 //return ReportError("Call station is locked");
3635
3636 //erase last character if specified
3637 if (text == "<" && InputCache.size() >= 1)
3638 InputCache.pop_back();
3639
3640 //add text to cache
3641 InputCache += text;
3642
3643 //automatically error if multiple special characters were entered and/or combined with numbers
3644 int StarCount = std::count(InputCache.begin(), InputCache.end(), '*');
3645 int MinCount = std::count(InputCache.begin(), InputCache.end(), '-');
3646 if ((StarCount > 1 || MinCount > 1) && InputCache.length() > 1)
3647 {
3648 keypad_timer->Stop();
3649 InputCache = "";
3650 KeypadError(1);
3651 return true;
3652
3653 //update indicator display
3655
3656 //start timeout timer
3657 keypad_timer->Start(2000, true);
3658
3659 return true;
3660 }
3661
3662
3663 //update indicator display
3665
3666 //verify that the floor entry is valid, error if not
3667 int result = 0;
3668 if (GetFloorFromID(InputCache, result) == false && InputCache != "*" && InputCache != "-")
3669 {
3670 keypad_timer->Stop();
3671 InputCache = "";
3672 KeypadError(1);
3673 return true;
3674 }
3675
3676 //start timeout timer
3677 keypad_timer->Start(TimerDelay * 1000.0f, true);
3678
3679 return true;
3680}
3681
3683{
3684 //process and clear input cache
3685
3686 Elevator* e = GetElevator();
3687
3688 //select recall floor if "0"
3689 if (InputCache == "0" || InputCache == "*")
3690 {
3691 e->SelectFloor(e->GetRecallFloor());
3692 InputCache = "";
3694 return;
3695 }
3696
3697 if (!IsNumeric(InputCache))
3698 {
3699 InputCache = "";
3700 KeypadError();
3701 return;
3702 }
3703
3704 //don't allow input values in the InvalidInput list
3705 for (size_t i = 0; i < InvalidInput.size(); i++)
3706 {
3707 if (InputCache == InvalidInput[i])
3708 {
3709 InputCache = "";
3710 KeypadError();
3711 return;
3712 }
3713 }
3714
3715 int floor = 0;
3716 GetFloorFromID(InputCache, floor);
3717 Requested(floor);
3718 e->SelectFloor(floor);
3719
3720 InputCache = "";
3721}
3722
3723bool ElevatorCar::GetFloorFromID(const std::string& floor, int& result)
3724{
3725 if (!IsNumeric(floor))
3726 return false;
3727
3728 int rawfloor = ToInt(floor);
3729
3730 //convert back to string, to strip off any leading 0's
3731 std::string converted = ToString(rawfloor);
3732
3733 Floor* floorobj = sbs->GetFloorManager()->GetByNumberID(converted);
3734 Floor* floorobj2 = sbs->GetFloorManager()->GetByID(converted);
3735 Floor* floorobj3 = sbs->GetFloorManager()->Get(rawfloor);
3736
3737 if (floorobj)
3738 {
3739 result = floorobj->Number; //get by number ID first
3740 return true;
3741 }
3742 else if (floorobj2)
3743 {
3744 result = floorobj2->Number; //next try floor ID
3745 return true;
3746 }
3747 else if (floorobj3)
3748 {
3749 result = rawfloor; //and last, get by raw floor number
3750 return true;
3751 }
3752
3753 return false;
3754}
3755
3757{
3758 //input timeout timer
3759
3761}
3762
3764{
3765 //if type is 0, standard error
3766 //if type is 1, invalid floor
3767
3768 std::string message = "XX";
3769 if (type == 1)
3770 message = "??";
3771
3772 UpdateKeypadIndicator(message);
3773}
3774
3775bool ElevatorCar::AddElevatorIDSigns(int door_number, bool relative, const std::string& texture_prefix, const std::string& direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset)
3776{
3777 //adds elevator ID signs at the specified position and direction for each serviced floor,
3778 //depending on if the given door number services the floor or not (unless door_number is 0)
3779
3780 Elevator* e = GetElevator();
3781
3782 Real x, z;
3783 if (relative == true)
3784 {
3785 x = GetPosition().x + CenterX;
3786 z = GetPosition().z + CenterZ;
3787 }
3788 else
3789 {
3790 x = CenterX;
3791 z = CenterZ;
3792 }
3793
3794 //make sure specified door exists before continuing
3795 if (door_number != 0)
3796 {
3797 if (DoorExists(door_number) == false)
3798 return ReportError("AddElevatorIDSigns: door " + ToString(door_number) + " does not exist");
3799 }
3800
3801 bool autosize_x, autosize_y;
3802 sbs->GetTextureManager()->GetAutoSize(autosize_x, autosize_y);
3803 sbs->GetTextureManager()->SetAutoSize(false, false);
3804
3805 for (size_t i = 0; i < ServicedFloors.size(); i++)
3806 {
3807 bool door_result = false;
3808 int floor = ServicedFloors[i];
3809 Real base = GetDestinationOffset(floor);
3810
3811 if (door_number != 0)
3812 door_result = ShaftDoorsExist(door_number, floor);
3813
3814 if ((door_number == 0 || door_result == true) && sbs->GetFloor(floor))
3815 {
3816 std::string texture = texture_prefix + e->ID;
3817 std::string tmpdirection = direction;
3818 SetCase(tmpdirection, false);
3819
3820 if (tmpdirection == "front" || tmpdirection == "left")
3821 sbs->DrawWalls(true, false, false, false, false, false);
3822 else
3823 sbs->DrawWalls(false, true, false, false, false, false);
3824
3825 if (tmpdirection == "front" || tmpdirection == "back")
3826 sbs->GetFloor(floor)->AddWall("Elevator ID Sign", texture, 0, x - (width / 2), z, x + (width / 2), z, height, height, base + voffset, base + voffset, 1, 1, false);
3827 else
3828 sbs->GetFloor(floor)->AddWall("Elevator ID Sign", texture, 0, x, z - (width / 2), x, z + (width / 2), height, height, base + voffset, base + voffset, 1, 1, false);
3829 sbs->ResetWalls();
3830 }
3831 }
3832 sbs->GetTextureManager()->SetAutoSize(autosize_x, autosize_y);
3833 return true;
3834}
3835
3836Reverb* ElevatorCar::AddReverb(const std::string &name, const std::string &type, const Vector3 &position, Real min_distance, Real max_distance)
3837{
3838 if (reverb)
3839 return 0;
3840
3841 //create a reverb object
3842 reverb = new Reverb(this, name, type, position, min_distance, max_distance, false);
3843 return reverb;
3844}
3845
3847{
3848 return reverb;
3849}
3850
3852{
3853 //remove the reverb
3854 //this does not delete the object
3855
3856 reverb = 0;
3857}
3858
3859
3860}
bool MouseDown()
Definition camera.cpp:1497
DoorWrapper * CreateDoor(bool open_state, const std::string &texture, const std::string &side_texture, Real thickness, const std::string &face_direction, const std::string &open_direction, Real open_speed, Real close_speed, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
Definition door.cpp:294
void Enabled(bool value, MeshObject *client=0)
KeypadTimer(const std::string &name, ElevatorCar *parent)
bool ReportError(const std::string &message)
void ResetNudgeTimer(bool start=true, int number=0)
void StopDoors(int number=0)
ElevatorDoor * lastdoor_result
Door * AddDoor(std::string name, const std::string &open_sound, const std::string &close_sound, bool open_state, const std::string &texture, const std::string &side_texture, Real thickness, const std::string &face_direction, const std::string &open_direction, bool rotate, Real open_speed, Real close_speed, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, Real tw, Real th, Real side_tw, Real side_th)
FloorIndicator * AddFloorIndicator(const std::string &texture_prefix, const std::string &blank_texture, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset)
void RemoveCameraTexture(CameraTexture *camtex)
std::string UpMoveSound
Definition elevatorcar.h:49
bool AddShaftDoors(int number, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
bool OpenDoorsEmergency(int number=0, int whichdoors=1, int floor=0, bool hold=false)
void EnableDoors(bool value)
void ChangeLight(int floor, bool value)
bool FinishShaftDoors(int number, bool DoorWalls=true, bool TrackWalls=true)
void HoldDoors(int number=0, bool sensor=false)
std::string DownMoveSound
Definition elevatorcar.h:50
void RemovePrimitive(Primitive *prim)
void ShaftDoorsEnabled(int number, int floor, bool value)
bool AddFloorSigns(int door_number, bool relative, const std::string &texture_prefix, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset)
void SetDirectionalIndicators(int floor, bool UpLight, bool DownLight)
void SetFloor(int floor, bool move_parent=true)
bool DoorExists(int number)
void SetMessageSound(bool type, bool direction, const std::string &filename)
std::string GetFloorDisplay()
void RemovePanel(ButtonPanel *panel)
std::vector< CameraTexture * > CameraTextureArray
Real GetDestinationOffset(int floor)
std::vector< Sound * > GetSound(const std::string &name)
bool GetSensorStatus(int number=0)
void CloseDoorsEmergency(int number=0, int whichdoors=1, int floor=0, bool hold=false)
std::vector< Door * > StdDoorArray
void RemoveServicedFloor(int number, bool remove_shaft_door=true)
Control * GetFloorButton(int floor)
bool PlayMessageSound(bool type)
Wall * AddWall(const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height1, Real height2, Real voffset1, Real voffset2, Real tw, Real th)
bool IsOnFloor(int floor, bool leveled=true)
bool OpenDoors(int number=0, int whichdoors=1, int floor=0, bool manual=false, bool hold=false)
ElevatorCar(Elevator *parent, int number)
std::string MusicDown
Definition elevatorcar.h:63
Door * CreateDoor(std::string name, const std::string &open_sound, const std::string &close_sound, bool rotate)
std::vector< int > DisplayFloors
Definition elevatorcar.h:44
Elevator * GetElevator()
void RemoveLight(Light *light)
ButtonPanel * CreateButtonPanel(const std::string &texture, int rows, int columns, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, Real spacingX, Real spacingY, Real tw, Real th)
void KeypadError(bool type=0)
bool IsInCar(const Vector3 &position, bool camera=false)
Wall * AddFloor(const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real voffset1, Real voffset2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool legacy_behavior=false)
std::string InputCache
void PlayStoppingSounds(bool emergency=false)
std::string AlarmSound
Definition elevatorcar.h:54
bool IndependentServiceOnOtherCar()
std::string UpStartSound
Definition elevatorcar.h:47
void EnableNudgeMode(bool value, int number=0)
void UpdateKeypadIndicator(const std::string &text, bool play_sound=true)
bool ShaftDoorsExist(int number, int floor, bool include_nonserviced=false)
bool Check(Vector3 &position)
std::vector< int > ServicedFloors
Definition elevatorcar.h:38
bool UseDoorMessageSounds
Definition elevatorcar.h:69
Indicator * AddKeypadIndicator(const std::string &sound, const std::string &texture_prefix, const std::string &blank_texture, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, Real timer_duration)
void AddDirectionalIndicators(bool relative, bool active_direction, bool single, bool vertical, const std::string &BackTexture, const std::string &uptexture, const std::string &uptexture_lit, const std::string &downtexture, const std::string &downtexture_lit, Real CenterX, Real CenterZ, Real voffset, const std::string &direction, Real BackWidth, Real BackHeight, bool ShowBack, Real tw, Real th)
std::string MusicUp
Definition elevatorcar.h:62
bool AreDoorsClosing(int number=0, bool car_doors=true, bool shaft_doors=true)
void ResetDoorState(int number=0)
bool CreateCar(int floor)
std::string OpenMessageSound
Definition elevatorcar.h:60
void RemoveFloorIndicator(FloorIndicator *indicator)
void Enabled(bool value)
std::vector< Primitive * > PrimArray
void EnableObjects(bool value)
std::string CloseMessageSound
Definition elevatorcar.h:61
void SetControls(const std::string &action_name)
void AddDisplayFloor(int floor)
Vector3 MusicPosition
Definition elevatorcar.h:43
std::vector< Light * > lights
void RemoveSound(Sound *sound)
ButtonPanel * GetPanel(int index)
Primitive * GetPrimitive(std::string name)
bool AddElevatorIDSigns(int door_number, bool relative, const std::string &texture_prefix, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset)
Elevator * parent
bool GetHoldStatus(int number=0)
void RemoveTrigger(Trigger *trigger)
bool ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
bool GetFloorFromID(const std::string &floor, int &result)
std::vector< CustomObject * > CustomObjectArray
CustomObject * GetCustomObject(std::string name)
void ShaftDoorsEnabledRange(int number, int floor, int range)
bool Input(const std::string &text)
Model * GetModel(std::string name)
bool DoorsStopped(int number=0)
Real GetDestinationAltitude(int floor)
void NotifyArrival(int floor, bool early=false, int direction=0)
bool IsNudgeModeActive(int number=0)
bool AreDoorsOpen(int number=0)
bool IsServicedFloor(int floor, bool report=true)
void UpdateDirectionalIndicators()
std::vector< DirectionalIndicator * > DirIndicatorArray
Light * AddLight(const std::string &name, int type)
void RemoveModel(Model *model)
DirectionalIndicator * AddDirectionalIndicator(bool active_direction, bool single, bool vertical, const std::string &BackTexture, const std::string &uptexture, const std::string &uptexture_lit, const std::string &downtexture, const std::string &downtexture_lit, Real CenterX, Real CenterZ, Real voffset, const std::string &direction, Real BackWidth, Real BackHeight, bool ShowBack, Real tw, Real th)
int GetFloorIndex(int floor)
void Requested(int floor)
void SetFloorSound(const std::string &prefix)
Primitive * AddPrimitive(const std::string &name)
std::vector< Trigger * > TriggerArray
std::vector< std::string > InvalidInput
bool RespondingToCall(int floor, int direction)
Model * AddModel(const std::string &name, const std::string &filename, bool center, Vector3 position, Vector3 rotation, Real max_render_distance=0, Real scale_multiplier=1, bool enable_physics=false, Real restitution=0, Real friction=0, Real mass=0)
Sound * AddSound(const std::string &name, const std::string &filename, Vector3 position, bool loop=true, Real volume=1.0, int speed=100, Real min_distance=1.0, Real max_distance=-1.0, Real doppler_level=0.0, Real cone_inside_angle=360, Real cone_outside_angle=360, Real cone_outside_volume=1.0, Vector3 direction=Vector3(0, 0, 0))
void RemoveCustomObject(CustomObject *object)
std::string FloorSound
Definition elevatorcar.h:57
DoorWrapper * AddDoors(int number, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real width, Real height, bool direction, Real tw, Real th)
std::string EmergencyStopSound
Definition elevatorcar.h:64
bool AddServicedFloor(int number, bool create_shaft_door=true)
Control * AddControl(const std::string &name, const std::string &sound, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, int selection_position, std::vector< std::string > &action_names, std::vector< std::string > &textures)
void RemoveDoor(Door *door)
std::vector< Control * > ControlArray
std::vector< Sound * > sounds
void RemoveControl(Control *control)
std::string UpMessageSound
Definition elevatorcar.h:58
void Chime(int number, int floor, bool direction, bool early=false)
MeshObject * Mesh
Door * GetStdDoor(int number)
bool AreShaftDoorsClosed(bool skip_current_floor=false)
void FlashIndicators(bool value)
bool AreDoorsOpening(int number=0, bool car_doors=true, bool shaft_doors=true)
DoorWrapper * FinishShaftDoor(int number, int floor, bool DoorWalls=true, bool TrackWalls=true)
void SetShaftDoors(int number, Real thickness, Real CenterX, Real CenterZ)
int AreDoorsMoving(int number=0, bool car_doors=true, bool shaft_doors=true)
bool AreShaftDoorsOpen(int number, int floor)
void AddShaftDoorsComponent(int number, 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)
bool IndependentServiceActive()
int GetServicedFloor(int index)
std::string UpStopSound
Definition elevatorcar.h:51
std::vector< ButtonPanel * > PanelArray
DoorWrapper * AddShaftDoor(int floor, int number, const std::string &lefttexture, const std::string &righttexture, Real tw, Real th)
Trigger * AddTrigger(const std::string &name, const std::string &sound_file, Vector3 &area_min, Vector3 &area_max, std::vector< std::string > &action_names)
std::vector< Model * > ModelArray
DoorWrapper * AddDoorComponent(int number, 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 AlarmSoundStop
Definition elevatorcar.h:55
void CloseDoors(int number=0, int whichdoors=1, int floor=0, bool manual=false, bool hold=false)
void Report(const std::string &message)
std::string DownMessageSound
Definition elevatorcar.h:59
std::string DownStopSound
Definition elevatorcar.h:52
Indicator * indicator
KeypadTimer * keypad_timer
CustomObject * AddCustomObject(const std::string &name, const Vector3 &position, const Vector3 &rotation, Real max_render_distance=0, Real scale_multiplier=1)
Reverb * AddReverb(const std::string &name, const std::string &type, const Vector3 &position, Real min_distance, Real max_distance)
DoorWrapper * FinishDoors(int number, bool DoorWalls=true, bool TrackWalls=true)
std::string DownStartSound
Definition elevatorcar.h:48
void SetBeepSound(const std::string &filename)
std::string IdleSound
Definition elevatorcar.h:53
std::string BeepSound
Definition elevatorcar.h:56
std::string Name
Definition elevatorcar.h:37
CameraTexture * AddCameraTexture(const std::string &name, int quality, Real fov, const Vector3 &position, bool use_rotation, const Vector3 &rotation)
Light * GetLight(const std::string &name)
void EnableDirectionalIndicators(bool value)
void ResetDoors(int number=0, bool sensor=false)
std::vector< ElevatorDoor * > DoorArray
std::vector< FloorIndicator * > FloorIndicatorArray
void RemoveElevatorDoor(ElevatorDoor *door)
ElevatorDoor * GetDoor(int number)
DoorWrapper * AddShaftDoorComponent(int number, 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)
void EnableSensor(bool value, int number=0)
void RemoveDirectionalIndicator(DirectionalIndicator *indicator)
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)
void EnableSensor(bool value, bool persistent=true)
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)
bool GetSensorStatus(bool persistent=true)
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)
void CloseDoors(int whichdoors=1, int floor=0, bool manual=false)
void Hold(bool sensor=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 Reset(bool sensor=false)
void Enabled(bool value)
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)
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)
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)
bool GetCallStatus(int floor, bool &up, bool &down)
bool Interlocks
Definition elevator.h:111
void Report(const std::string &message)
std::string FloorSkipText
Definition elevator.h:365
bool GetArrivalDirection(int floor)
bool OnRecallFloor()
DynamicMesh * DoorContainer
Definition elevator.h:351
bool UseFloorSkipText
Definition elevator.h:69
int QueuePositionDirection
Definition elevator.h:40
std::vector< QueueEntry > UpQueue
Definition elevator.h:302
bool GetDestinationDispatch()
ElevatorCar * GetCar(int number)
int GetActiveCallFloor()
bool SelectFloor(int floor)
bool IsQueueActive()
bool Stop(bool emergency=false)
Definition elevator.cpp:812
int FireServicePhase2Car
Definition elevator.h:79
bool AutoAdjustSound
Definition elevator.h:116
bool LimitQueue
Definition elevator.h:104
int GetRecallFloor()
bool DownPeak
Definition elevator.h:73
bool IndependentService
Definition elevator.h:74
void RemoveCar(ElevatorCar *car)
bool NotifyLate
Definition elevator.h:97
int ActiveDirection
Definition elevator.h:95
bool InServiceMode()
int AssignedShaft
Definition elevator.h:56
int LastChimeDirection
Definition elevator.h:106
void MoveObjects(Real offset)
std::string ID
Definition elevator.h:37
bool InspectionService
Definition elevator.h:76
int FireServicePhase2
Definition elevator.h:78
std::vector< QueueEntry > DownQueue
Definition elevator.h:303
bool IsMoving
Definition elevator.h:60
Shaft * GetShaft()
int GetActiveCallDirection()
int IndependentServiceCar
Definition elevator.h:75
bool SkipFloorSound
Definition elevator.h:117
bool IsServicedFloor(int floor, bool report=true)
bool ReportError(const std::string &message)
int LastQueueDirection
Definition elevator.h:41
int GetActiveCallType()
Real ElevatorRate
Definition elevator.h:55
bool ChimeOnArrival
Definition elevator.h:118
int FireServicePhase1
Definition elevator.h:77
int NotifyEarly
Definition elevator.h:96
Real DownSpeed
Definition elevator.h:44
bool OpenOnStart
Definition elevator.h:108
Floor * GetByID(const std::string &id)
Definition manager.cpp:185
Floor * GetByNumberID(const std::string &id)
Definition manager.cpp:198
Floor * Get(int number)
Definition manager.cpp:108
DirectionalIndicator * AddDirectionalIndicator(int elevator, int car, bool relative, bool active_direction, bool single, bool vertical, const std::string &BackTexture, const std::string &uptexture, const std::string &uptexture_lit, const std::string &downtexture, const std::string &downtexture_lit, Real CenterX, Real CenterZ, Real voffset, const std::string &direction, Real BackWidth, Real BackHeight, bool ShowBack, Real tw, Real th)
Definition floor.cpp:1161
int Number
Definition floor.h:36
Real GetBase(bool relative=false)
Definition floor.cpp:1140
std::string ID
Definition floor.h:38
void SetDirectionalIndicators(int elevator, int car, bool UpLight, bool DownLight)
Definition floor.cpp:1196
Wall * AddWall(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 voffset1, Real voffset2, Real tw, Real th, bool isexternal)
Definition floor.cpp:347
void Update(const std::string &text, bool play_sound=true)
void Enabled(bool value)
Definition light.cpp:136
bool InBoundingBox(const Vector3 &pos, bool check_y)
Definition mesh.cpp:1018
void Enabled(bool value)
Definition mesh.cpp:154
Real HitBeam(const Vector3 &origin, const Vector3 &direction, Real max_distance)
Definition mesh.cpp:760
Real GetHeight()
Definition mesh.cpp:728
bool ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
Definition mesh.cpp:691
Wall * CreateWallObject(const std::string &name)
Definition mesh.cpp:208
bool load_error
Definition model.h:32
const std::string & GetName()
Definition object.cpp:53
virtual void Report(const std::string &message)
Definition object.cpp:78
void SetName(const std::string &name)
Definition object.cpp:72
bool parent_deleting
Definition object.h:64
virtual void Move(const Vector3 &vector, Real speed=1.0)
Definition object.cpp:253
void LoopChildren()
Definition object.cpp:579
virtual void SetPositionY(Real value)
Definition object.cpp:313
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:321
void SetPositionRelative(const Vector3 &position)
Definition object.cpp:287
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
virtual void Enabled(bool value)
Definition object.h:110
bool GetPower()
Definition sbs.cpp:4701
FloorManager * GetFloorManager()
Definition sbs.cpp:4533
bool IsRunning
Definition sbs.h:157
std::string GetConfigString(const std::string &key, const std::string &default_value)
Definition sbs.cpp:3238
int CarNumber
Definition sbs.h:166
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
bool IsValidFloor(int floor)
Definition sbs.cpp:2492
Floor * GetFloor(int number)
Definition sbs.cpp:1739
bool FastDelete
Definition sbs.h:188
TextureManager * GetTextureManager()
Definition sbs.cpp:4558
Camera * camera
Definition sbs.h:160
int GetFloorNumber(Real altitude, int lastfloor=0, bool checklastfloor=false)
Definition sbs.cpp:1584
int ElevatorNumber
Definition sbs.h:165
bool GetConfigBool(const std::string &key, bool default_value)
Definition sbs.cpp:3243
bool InElevator
Definition sbs.h:163
void DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
Definition sbs.cpp:1833
bool AddFloorMain(Wall *wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real altitude1, Real altitude2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool autosize, bool legacy_behavior=false)
Definition sbs.cpp:921
bool ElevatorSync
Definition sbs.h:167
bool Verbose
Definition sbs.h:186
int endfloor
Definition shaft.h:36
bool IsValidFloor(int floor)
Definition shaft.cpp:433
void Pause(bool value=true)
Definition sound.cpp:223
void Reset()
Definition sound.cpp:378
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 PlayQueued(const std::string &filename, bool stop=true, bool loop=false)
Definition sound.cpp:490
bool IsLoaded()
Definition sound.cpp:475
void ProcessQueue()
Definition sound.cpp:512
void SetSpeed(int percent)
Definition sound.cpp:273
void SetDopplerLevel(Real level)
Definition sound.cpp:462
void SetLoopState(bool value)
Definition sound.cpp:204
void SetPlayPosition(Real percent)
Definition sound.cpp:439
void SetConeSettings(Real inside_angle=360.0, Real outside_angle=360.0, Real outside_volume=1.0)
Definition sound.cpp:196
void SetVolume(Real value)
Definition sound.cpp:138
bool IsPlaying()
Definition sound.cpp:254
void SetDirection(const Vector3 &direction)
Definition sound.cpp:179
void SetDistances(Real min, Real max)
Definition sound.cpp:158
void SetAutoSize(bool x, bool y)
Definition texture.cpp:1075
void GetAutoSize(bool &x, bool &y)
Definition texture.cpp:1082
void Start(int milliseconds=-1, bool oneshot=false)
Definition timer.cpp:49
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
void ReplaceAll(std::string &string, const std::string &original, const std::string &replacement)
Definition globals.cpp:201
int ToInt(const std::string &string)
Definition globals.cpp:402
void SetCase(std::string &string, bool uppercase)
Definition globals.cpp:172
std::string ToString(int number)
Definition globals.cpp:279
std::string SetCaseCopy(std::string string, bool uppercase)
Definition globals.cpp:165
bool IsNumeric(char character)
Definition globals.cpp:48
void TrimString(std::string &string)
Definition globals.cpp:188
#define SBS_PROFILE(name)
Definition profiler.h:131