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 != "" && alarm)
687 {
689 alarm->SetLoopState(true);
690 alarm->Play();
691 }
692 }
693 else if (sbs->camera->MouseDown() == false)
694 {
695 //stop alarm
696 AlarmActive = false;
697 if (AlarmSound != "" && alarm)
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 if (idlesound && musicsound)
740 {
741 idlesound->Stop();
742 musicsound->Stop();
743 }
744 }
745
746 ControlPressActive = false;
747
748 //perform first-run tasks
749 if (FirstRun == true)
750 {
751 FirstRun = false;
752
753 if (parent->OpenOnStart == true)
754 OpenDoors();
755 }
756
757 //play car idle sound if in elevator, or if doors open
758 if (IdleSound != "" && sbs->GetPower() == true && idlesound)
759 {
760 if (idlesound->IsPlaying() == false && Fan == true)
761 {
762 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving(0, true, false) != 0)
763 {
764 if (sbs->Verbose)
765 Report("playing car idle sound");
766
767 if (idlesound->IsLoaded() == false)
769
770 idlesound->SetLoopState(true);
771 idlesound->Play();
772 }
773 }
774 else
775 {
776 if (Fan == false && idlesound->IsPlaying() == true)
777 {
778 if (sbs->Verbose)
779 Report("stopping car idle sound");
780 idlesound->Stop();
781 }
782 else if (InCar() == false && AreDoorsOpen() == false && AreDoorsMoving() == 0)
783 {
784 if (sbs->Verbose)
785 Report("stopping car idle sound");
786 idlesound->Stop();
787 }
788 }
789 }
790
791 //music processing
792 if ((MusicUp != "" || MusicDown != "") && sbs->GetPower() == true && musicsound)
793 {
794 if (MusicAlwaysOn == false) //standard mode
795 {
796 //play music sound if in elevator, or if doors open
797 if (musicsound->IsPlaying() == false && MusicOn == true && ((MusicOnMove == true && parent->IsMoving == true) || MusicOnMove == false))
798 {
799 if (parent->InServiceMode() == false)
800 {
801 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving() != 0)
802 {
803 if (sbs->Verbose)
804 Report("playing music");
805
806 int direction = parent->ActiveDirection;
807
808 //load music if not already loaded, or if music direction has changed
809 if (musicsound->IsLoaded() == false || (last_music_direction != direction && MusicOn == true))
810 {
811 if (direction == 0 && last_music_direction != 0)
812 direction = last_music_direction;
813
814 if (direction >= 0)
816 else
818
819 last_music_direction = direction;
820 }
821
823 musicsound->Play(false);
824 }
825 }
826 }
827 else
828 {
829 if ((MusicOn == false || parent->InServiceMode() == true || (MusicOnMove == true && parent->IsMoving == false)) && musicsound->IsPlaying() == true)
830 {
831 if (sbs->Verbose)
832 Report("stopping music");
833 musicsound->Pause();
834 }
835 else if (InCar() == false && AreDoorsOpen() == false && AreDoorsMoving() == 0)
836 {
837 //turn off music if outside elevator car and doors are closed
838 if (sbs->Verbose)
839 Report("stopping music");
840 musicsound->Pause();
841 }
842 else if (MusicOn == true && MusicOnMove == false && musicsound->IsPlaying() == true)
843 {
844 //stop music if elevator changes direction while music is on
846 musicsound->Pause();
847 }
848 }
849 }
850 else //always-on mode
851 {
852 if (musicsound->IsPlaying() == false && MusicOn == true && MusicOnMove == false)
853 {
854 //enable music if in always-on mode
855
856 if (parent->InServiceMode() == false)
857 {
858 if (sbs->Verbose)
859 Report("playing music");
860
861 int direction = parent->ActiveDirection;
862
863 //load music if not already loaded, or if music direction has changed
864 if (musicsound->IsLoaded() == false || (last_music_direction != direction && MusicOn == true))
865 {
866 if (direction == 0 && last_music_direction != 0)
867 direction = last_music_direction;
868
869 if (direction >= 0)
871 else
873
874 last_music_direction = direction;
875 }
876
878 musicsound->SetVolume(0.0);
879 musicsound->Play(false);
880 }
881 }
882 else if (MusicOn == true && MusicOnMove == false && musicsound->IsPlaying() == true)
883 {
885 {
886 //stop music if elevator changes direction while music is on
887 musicsound->Pause();
888 }
889 else
890 {
891 //manage music volume state
892 //(turn on volume only if inside the elevator, or if the doors are open)
893 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving() != 0)
894 musicsound->SetVolume(1.0);
895 else
896 musicsound->SetVolume(0.0);
897 }
898 }
899 }
900 }
901
902 //turn on lights if in elevator, or if doors are open
903 for (size_t i = 0; i < lights.size(); i++)
904 {
905 if (!lights[i])
906 continue;
907
908 if (lights[i]->IsEnabled() == false)
909 {
910 if (InCar() == true || AreDoorsOpen() == true || AreDoorsMoving(0, true, false) != 0)
911 {
912 if (sbs->Verbose)
913 Report("enabling lights");
914
915 lights[i]->Enabled(true);
916 }
917 }
918 else
919 {
920 if (InCar() == false && AreDoorsOpen() == false && AreDoorsMoving() == 0)
921 {
922 if (sbs->Verbose)
923 Report("disabling lights");
924 lights[i]->Enabled(false);
925 }
926 }
927 }
928
929 //process alarm
930 if (AlarmActive == true)
931 Alarm();
932
933 //process door open/close holds
934 if (doorhold_direction > 0)
935 OpenDoors();
936 if (doorhold_direction < 0)
937 CloseDoors();
938
939 //door operations
940 for (int i = 1; i <= NumDoors; i++)
941 {
942 ElevatorDoor *door = GetDoor(i);
943 if (door)
944 door->Loop();
945
946 //reset door timer if peak mode is enabled and a movement is pending
947 if ((parent->UpPeak == true || parent->DownPeak == true))
948 {
949 if ((parent->UpQueue.empty() == false || parent->DownQueue.empty() == false) && (AreDoorsOpen() == true && AreDoorsMoving() == 0))
950 {
951 if (door)
952 {
953 if (door->TimerIsRunning() == false)
954 door->Reset();
955 }
956 }
957 }
958 }
959
960 //run child object runloops
961 if (IsEnabled == true)
962 LoopChildren();
963
964 //process door sensors
965 for (size_t i = 0; i < DoorArray.size(); i++)
966 {
967 if (DoorArray[i])
968 DoorArray[i]->CheckSensor();
969 }
970
971 //process queued sounds
972 if (announcesnd)
974
975 //reset message sound status
976 DirMessageSound = false;
977 DoorMessageSound = false;
978}
979
980void ElevatorCar::Enabled(bool value)
981{
982 //shows/hides elevator car
983
984 if (IsEnabled == value)
985 return;
986
987 if (sbs->Verbose)
988 {
989 if (value == true)
990 Report("enabling car");
991 else
992 Report("disabling car");
993 }
994
995 Mesh->Enabled(value);
996 EnableDoors(value);
997 IsEnabled = value;
998
999 //floor indicators
1000 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
1001 {
1002 if (FloorIndicatorArray[i])
1003 FloorIndicatorArray[i]->Enabled(value);
1004 }
1005
1006 //interior directional indicators
1008
1009 if (value == false)
1010 EnableObjects(false);
1011}
1012
1014{
1015 //enable or disable interior objects, such as floor indicators and button panels
1016
1017 if (AutoEnable == false)
1018 return;
1019
1020 //SBS_PROFILE("ElevatorCar::EnableObjects");
1021 if (sbs->Verbose)
1022 {
1023 if (value == true)
1024 Report("enabling objects");
1025 else
1026 Report("disabling objects");
1027 }
1028
1029 //floor indicators
1030 /*for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
1031 {
1032 if (FloorIndicatorArray[i])
1033 FloorIndicatorArray[i]->Enabled(value);
1034 }*/
1035
1036 //interior directional indicators
1037 //EnableDirectionalIndicators(value);
1038
1039 //controls
1040 for (size_t i = 0; i < ControlArray.size(); i++)
1041 {
1042 if (ControlArray[i])
1043 ControlArray[i]->Enabled(value);
1044 }
1045
1046 //triggers
1047 for (size_t i = 0; i < TriggerArray.size(); i++)
1048 {
1049 if (TriggerArray[i])
1050 TriggerArray[i]->Enabled(value);
1051 }
1052
1053 //models
1054 for (size_t i = 0; i < ModelArray.size(); i++)
1055 {
1056 if (ModelArray[i])
1057 ModelArray[i]->Enabled(value);
1058 }
1059
1060 //panels
1061 for (size_t i = 0; i < PanelArray.size(); i++)
1062 PanelArray[i]->Enabled(value);
1063
1064 //primitives
1065 for (size_t i = 0; i < PrimArray.size(); i++)
1066 {
1067 if (PrimArray[i])
1068 PrimArray[i]->Enabled(value);
1069 }
1070
1071 //custom objects
1072 for (size_t i = 0; i < CustomObjectArray.size(); i++)
1073 {
1074 if (CustomObjectArray[i])
1075 CustomObjectArray[i]->Enabled(value);
1076 }
1077
1078 //sounds
1079 for (size_t i = 0; i < sounds.size(); i++)
1080 {
1081 if (sounds[i])
1082 {
1083 if (sounds[i]->GetLoopState() == true)
1084 {
1085 if (value == false)
1086 sounds[i]->Stop();
1087 else
1088 sounds[i]->Play();
1089 }
1090 }
1091 }
1092
1093 //reverb
1094 if (reverb)
1095 reverb->Enabled(value);
1096}
1097
1099{
1100 //updates all floor indicators
1101
1102 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
1103 {
1104 if (FloorIndicatorArray[i])
1105 FloorIndicatorArray[i]->Update();
1106 }
1107}
1108
1110{
1111 //returns highest serviced floor
1112
1113 if (ServicedFloors.empty() == true)
1114 return 0;
1115
1116 return ServicedFloors[ServicedFloors.size() - 1];
1117}
1118
1120{
1121 //returns lowest serviced floor
1122
1123 if (ServicedFloors.empty() == true)
1124 return 0;
1125
1126 return ServicedFloors[0];
1127}
1128
1129void 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)
1130{
1131 //create external directional indicators on all serviced floors
1132
1133 if (sbs->Verbose)
1134 Report("adding directional indicators");
1135
1136 for (size_t i = 0; i < ServicedFloors.size(); i++)
1137 {
1138 if (sbs->GetFloor(ServicedFloors[i]))
1139 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);
1140 }
1141}
1142
1143DirectionalIndicator* 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)
1144{
1145 //create a directional indicator inside the elevator
1146
1147 if (sbs->Verbose)
1148 Report("adding interior directional indicator");
1149
1150 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);
1151 DirIndicatorArray.emplace_back(indicator);
1152 return indicator;
1153}
1154
1155void ElevatorCar::SetDirectionalIndicators(int floor, bool UpLight, bool DownLight)
1156{
1157 //set light status of exterior and interior directional indicators
1158 //for interior indicators, the value of floor is passed to the indicator for checks
1159
1160 //exterior indicators
1161 if (sbs->GetFloor(floor))
1162 sbs->GetFloor(floor)->SetDirectionalIndicators(parent->Number, Number, UpLight, DownLight);
1163
1164 //interior indicators
1165 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
1166 {
1168
1169 if (indicator)
1170 {
1171 if (indicator->ActiveDirection == false)
1172 {
1173 indicator->floor = floor;
1174 indicator->DownLight(DownLight);
1175 indicator->UpLight(UpLight);
1176 }
1177 }
1178 }
1179}
1180
1182{
1183 //updates all interior active direction indicators
1184
1185 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
1186 {
1188
1189 if (indicator)
1190 {
1191 if (indicator->ActiveDirection == true)
1192 {
1193 if (parent->ActiveDirection == 1)
1194 {
1195 indicator->DownLight(false);
1196 indicator->UpLight(true);
1197 }
1198 if (parent->ActiveDirection == 0)
1199 {
1200 indicator->DownLight(false);
1201 indicator->UpLight(false);
1202 }
1203 if (parent->ActiveDirection == -1)
1204 {
1205 indicator->DownLight(true);
1206 indicator->UpLight(false);
1207 }
1208 }
1209 }
1210 }
1211}
1212
1214{
1215 //turn on/off all interior directional indicators
1216
1217 if (sbs->Verbose)
1218 {
1219 if (value == true)
1220 Report("enabling interior directional indicators");
1221 else
1222 Report("disabling interior directional indicators");
1223 }
1224
1225 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
1226 {
1227 if (DirIndicatorArray[i])
1228 DirIndicatorArray[i]->Enabled(value);
1229 }
1230}
1231
1233{
1234 //get elevator door object
1235
1236 //return cached check if number is the same
1237 if (lastdoor_number == number && lastdoor_result)
1238 return lastdoor_result;
1239
1240 if (number > 0 && number <= (int)DoorArray.size())
1241 {
1242 if (DoorArray[number - 1])
1243 {
1244 lastdoor_result = DoorArray[number - 1];
1245 lastdoor_number = number;
1246 return lastdoor_result;
1247 }
1248 }
1249 return 0;
1250}
1251
1252bool ElevatorCar::OpenDoorsEmergency(int number, int whichdoors, int floor, bool hold)
1253{
1254 //Simulates manually prying doors open.
1255 //Slowly opens the elevator doors no matter where elevator is.
1256 //If lined up with shaft doors, then opens the shaft doors also
1257
1258 //WhichDoors is the doors to move:
1259 //1 = both shaft and elevator doors
1260 //2 = only elevator doors
1261 //3 = only shaft doors
1262
1263 return OpenDoors(number, whichdoors, floor, true, hold);
1264}
1265
1266void ElevatorCar::CloseDoorsEmergency(int number, int whichdoors, int floor, bool hold)
1267{
1268 //Simulates manually closing doors.
1269 //Slowly closes the elevator doors no matter where elevator is.
1270 //If lined up with shaft doors, then closes the shaft doors also
1271
1272 //WhichDoors is the doors to move:
1273 //1 = both shaft and elevator doors
1274 //2 = only elevator doors
1275 //3 = only shaft doors
1276
1277 CloseDoors(number, whichdoors, floor, true, hold);
1278}
1279
1280bool ElevatorCar::OpenDoors(int number, int whichdoors, int floor, bool manual, bool hold)
1281{
1282 //Opens elevator doors
1283
1284 //if manual is true, then it simulates manually prying doors open,
1285 //Slowly opens the elevator doors no matter where elevator is,
1286 //and if lined up with shaft doors, then opens the shaft doors also.
1287 //if hold is true, sets 'hold' state requiring button to be held to keep doors opening
1288
1289 //WhichDoors is the doors to move:
1290 //1 = both shaft and elevator doors
1291 //2 = only elevator doors
1292 //3 = only shaft doors
1293
1294 //only run if power is enabled
1295 if (sbs->GetPower() == false && manual == false)
1296 return false;
1297
1298 //require open button to be held for fire service phase 2 if not on recall floor
1299 if (FirePhase2Active() == 1 && parent->OnRecallFloor() == false && manual == false)
1300 hold = true;
1301
1302 if (parent->Interlocks == true)
1303 {
1304 //if elevator is moving and interlocks are enabled, stop elevator
1305 if (parent->IsMoving == true && parent->OnFloor == false)
1306 parent->Stop(true);
1307 }
1308
1309 int start = number, end = number;
1310 if (number == 0)
1311 {
1312 start = 1;
1313 end = NumDoors;
1314 }
1315 if (doorhold_direction == 0)
1316 {
1317 if (ControlPressActive == true && parent->AutoDoors == true && parent->InServiceMode() == false && hold == false && manual == false && whichdoors != 3 && DoorsStopped(number) == false)
1318 {
1320
1321 if (AreDoorsOpen(number) == true && AreDoorsMoving(number) == false)
1322 return true; //exit to skip an extra open door call
1323 }
1324
1325 if (hold == true)
1327
1328 if (doorhold_direction > 0)
1329 {
1330 //set persistent values
1331 doorhold_whichdoors = whichdoors;
1332 doorhold_floor = floor;
1333 doorhold_manual = manual;
1334 }
1335
1336 for (int i = start; i <= end; i++)
1337 {
1338 if (GetDoor(i))
1339 GetDoor(i)->OpenDoors(whichdoors, floor, manual);
1340 else
1341 ReportError("Invalid door " + ToString(i));
1342 }
1343 }
1344 else if (doorhold_direction == 1 && sbs->camera->MouseDown() == false)
1345 {
1346 //require button to be held down to open doors
1347
1348 bool closedstate = false;
1349
1350 for (int i = start; i <= end; i++)
1351 {
1352 //check door states first
1353 if (GetDoor(i))
1354 {
1355 if (GetDoor(i)->AreDoorsOpen() == false)
1356 {
1357 closedstate = true;
1358 break;
1359 }
1360 }
1361 else
1362 ReportError("Invalid door " + ToString(i));
1363 }
1364
1365 for (int i = start; i <= end; i++)
1366 {
1367 //close doors using persistent values, if button is released before doors are fully open
1368 if (GetDoor(i))
1369 {
1370 if (closedstate == true)
1372 }
1373 else
1374 ReportError("Invalid door " + ToString(i));
1375 }
1376
1377 //reset persistent values
1380 doorhold_floor = 0;
1381 doorhold_manual = false;
1382 }
1383 else if (doorhold_direction == 2)
1384 {
1385 //hold doors while button is held
1386
1387 if (AreDoorsOpen(number) == true && AreDoorsMoving(number) == false)
1388 {
1389 if (sbs->camera->MouseDown() == true)
1390 {
1391 //hold doors while button is held down
1392 HoldDoors(number);
1393 return true;
1394 }
1395 else
1396 {
1397 //run door open again to reset doors (turn off hold) if button is released
1398 for (int i = start; i <= end; i++)
1399 {
1400 //open doors using persistent values
1401 if (GetDoor(i))
1403 else
1404 ReportError("Invalid door " + ToString(i));
1405 }
1406 }
1407 }
1408
1409 if (sbs->camera->MouseDown() == false)
1410 {
1411 //reset persistent values
1414 doorhold_floor = 0;
1415 doorhold_manual = false;
1416 }
1417 }
1418
1419 return true;
1420}
1421
1422void ElevatorCar::CloseDoors(int number, int whichdoors, int floor, bool manual, bool hold)
1423{
1424 //Closes elevator doors
1425 //if hold is true, sets 'hold' state requiring button to be held to keep doors closing
1426
1427 //WhichDoors is the doors to move:
1428 //1 = both shaft and elevator doors
1429 //2 = only elevator doors
1430 //3 = only shaft doors
1431
1432 //only run if power is enabled
1433 if (sbs->GetPower() == false && manual == false)
1434 return;
1435
1436 //turn on hold option for certain modes
1437 if ((IndependentServiceActive() == true || FirePhase2Active() == 1) && manual == false)
1438 hold = true;
1439
1440 int start = number, end = number;
1441 if (number == 0)
1442 {
1443 start = 1;
1444 end = NumDoors;
1445 }
1446 if (doorhold_direction == 0)
1447 {
1448 for (int i = start; i <= end; i++)
1449 {
1450 if (GetDoor(i))
1451 GetDoor(i)->CloseDoors(whichdoors, floor, manual);
1452 else
1453 ReportError("Invalid door " + ToString(i));
1454 }
1455
1456 if (hold == true)
1457 {
1458 //set persistent values
1459 doorhold_direction = -1;
1460 doorhold_whichdoors = whichdoors;
1461 doorhold_floor = floor;
1462 doorhold_manual = manual;
1463 }
1464 }
1465 else if (doorhold_direction == -1 && sbs->camera->MouseDown() == false)
1466 {
1467 bool openstate = false;
1468 for (int i = start; i <= end; i++)
1469 {
1470 //check door states first
1471 if (GetDoor(i))
1472 {
1473 if (GetDoor(i)->AreDoorsOpen() == true)
1474 {
1475 openstate = true;
1476 break;
1477 }
1478 }
1479 else
1480 ReportError("Invalid door " + ToString(i));
1481 }
1482
1483 if (openstate == true)
1484 {
1485 for (int i = start; i <= end; i++)
1486 {
1487 //open doors using persistent values, if button is released before doors are fully closed
1488 if (GetDoor(i))
1489 {
1490 if (GetDoor(i)->AreDoorsMoving(0) == true)
1492 }
1493 else
1494 ReportError("Invalid door " + ToString(i));
1495 }
1496 }
1497
1498 //reset persistent values
1501 doorhold_floor = 0;
1502 doorhold_manual = false;
1503 }
1504}
1505
1507{
1508 //stops doors that are currently moving; can only be used for manual/emergency movements
1509 //this basically just resets the door internals
1510
1511 int start = number, end = number;
1512 if (number == 0)
1513 {
1514 start = 1;
1515 end = NumDoors;
1516 }
1517 for (int i = start; i <= end; i++)
1518 {
1519 if (GetDoor(i))
1520 GetDoor(i)->StopDoors();
1521 else
1522 ReportError("Invalid door " + ToString(i));
1523 }
1524}
1525
1526DoorWrapper* 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)
1527{
1528 //adds elevator doors specified at a relative central position (off of elevator origin)
1529 //if direction is false, doors are on the left/right side; otherwise front/back
1530
1531 if (GetDoor(number))
1532 return GetDoor(number)->AddDoors(lefttexture, righttexture, thickness, CenterX, CenterZ, width, height, direction, tw, th);
1533 else
1534 ReportError("Invalid door " + ToString(number));
1535 return 0;
1536}
1537
1538bool ElevatorCar::AddShaftDoors(int number, const std::string &lefttexture, const std::string &righttexture, Real thickness, Real CenterX, Real CenterZ, Real voffset, Real tw, Real th)
1539{
1540 //adds shaft's elevator doors specified at a relative central position (off of elevator origin)
1541 //uses some parameters (width, height, direction) from AddDoors function
1542
1543 if (GetDoor(number))
1544 {
1545 Report("Adding shaft doors...");
1546 return GetDoor(number)->AddShaftDoors(lefttexture, righttexture, thickness, CenterX, CenterZ, voffset, tw, th);
1547 }
1548 else
1549 ReportError("Invalid door " + ToString(number));
1550 return false;
1551}
1552
1553DoorWrapper* ElevatorCar::AddShaftDoor(int floor, int number, const std::string &lefttexture, const std::string &righttexture, Real tw, Real th)
1554{
1555 //adds a single elevator shaft door on the specified floor, with position and thickness parameters first specified
1556 //by the SetShaftDoors command.
1557
1558 if (IsServicedFloor(floor) == true && GetDoor(number))
1559 return GetDoor(number)->AddShaftDoor(floor, lefttexture, righttexture, tw, th);
1560 else
1561 return 0;
1562}
1563
1564DoorWrapper* 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)
1565{
1566 //adds a single elevator shaft door on the specified floor, with position and thickness parameters first specified
1567 //by the SetShaftDoors command.
1568
1569 if (IsServicedFloor(floor) == true && GetDoor(number))
1570 return GetDoor(number)->AddShaftDoor(floor, lefttexture, righttexture, thickness, CenterX, CenterZ, voffset, tw, th);
1571 else
1572 return 0;
1573}
1574
1575void ElevatorCar::ShaftDoorsEnabled(int number, int floor, bool value)
1576{
1577 //turns shaft elevator doors on/off
1578
1579 SBS_PROFILE("Elevator::ShaftDoorsEnabled");
1580
1581 int start = number, end = number;
1582 if (number == 0)
1583 {
1584 start = 1;
1585 end = NumDoors;
1586 }
1587 for (int i = start; i <= end; i++)
1588 {
1589 ElevatorDoor *door = GetDoor(i);
1590 if (door)
1591 door->ShaftDoorsEnabled(floor, value);
1592 else
1593 ReportError("Invalid door " + ToString(i));
1594 }
1595}
1596
1597void ElevatorCar::ShaftDoorsEnabledRange(int number, int floor, int range)
1598{
1599 //turn on a range of floors
1600 //if range is 3, show shaft door on current floor (floor), and 1 floor below and above (3 total floors)
1601 //if range is 1, show door on only the current floor (floor)
1602
1603 SBS_PROFILE("Elevator::ShaftDoorsEnabledRange");
1604
1605 int start = number, end = number;
1606 if (number == 0)
1607 {
1608 start = 1;
1609 end = NumDoors;
1610 }
1611 for (int i = start; i <= end; i++)
1612 {
1613 ElevatorDoor *door = GetDoor(i);
1614 if (door)
1615 door->ShaftDoorsEnabledRange(floor, range);
1616 else
1617 ReportError("Invalid door " + ToString(i));
1618 }
1619}
1620
1622{
1623 //returns the internal door state
1624
1625 SBS_PROFILE("Elevator::AreDoorsOpen");
1626
1627 int start = number, end = number;
1628 if (number == 0)
1629 {
1630 start = 1;
1631 end = NumDoors;
1632 }
1633 for (int i = start; i <= end; i++)
1634 {
1635 ElevatorDoor *door = GetDoor(i);
1636 if (door)
1637 {
1638 if (door->AreDoorsOpen() == true)
1639 return true;
1640 }
1641 else
1642 ReportError("Invalid door " + ToString(i));
1643 }
1644 return false;
1645}
1646
1647bool ElevatorCar::AreShaftDoorsOpen(int number, int floor)
1648{
1649 //returns the internal shaft door state
1650
1651 SBS_PROFILE("Elevator::AreShaftDoorsOpen");
1652
1653 int start = number, end = number;
1654 if (number == 0)
1655 {
1656 start = 1;
1657 end = NumDoors;
1658 }
1659 for (int i = start; i <= end; i++)
1660 {
1661 ElevatorDoor *door = GetDoor(i);
1662 if (door)
1663 {
1664 if (door->AreShaftDoorsOpen(floor) == true)
1665 return true;
1666 }
1667 else
1668 ReportError("Invalid door " + ToString(i));
1669 }
1670 return false;
1671}
1672
1673bool ElevatorCar::AreShaftDoorsClosed(bool skip_current_floor)
1674{
1675 //return true if all shaft doors are closed and not moving
1676
1677 for (size_t i = 0; i < DoorArray.size(); i++)
1678 {
1679 if (DoorArray[i])
1680 {
1681 if (DoorArray[i]->AreShaftDoorsClosed(skip_current_floor) == false)
1682 return false;
1683 }
1684 }
1685 return true;
1686}
1687
1688void ElevatorCar::Chime(int number, int floor, bool direction, bool early)
1689{
1690 //play chime sound on specified floor
1691
1692 SBS_PROFILE("Elevator::Chime");
1693
1694 //only run if power is enabled
1695 if (sbs->GetPower() == false)
1696 return;
1697
1698 int start = number, end = number;
1699 if (number == 0)
1700 {
1701 start = 1;
1702 end = NumDoors;
1703 }
1704 for (int i = start; i <= end; i++)
1705 {
1706 ElevatorDoor *door = GetDoor(i);
1707 if (door)
1708 {
1709 if (early == false)
1710 door->Chime(floor, direction);
1711 else
1712 door->EarlyChime(floor, direction);
1713 }
1714 else
1715 ReportError("Invalid door " + ToString(i));
1716 }
1717 if (direction == true)
1719 else
1721}
1722
1723void ElevatorCar::ResetDoors(int number, bool sensor)
1724{
1725 //reset elevator door timer
1726
1727 //only run if power is enabled
1728 if (sbs->GetPower() == false)
1729 return;
1730
1731 int start = number, end = number;
1732 if (number == 0)
1733 {
1734 start = 1;
1735 end = NumDoors;
1736 }
1737 for (int i = start; i <= end; i++)
1738 {
1739 ElevatorDoor *door = GetDoor(i);
1740 if (door)
1741 door->Reset(sensor);
1742 else
1743 ReportError("Invalid door " + ToString(i));
1744 }
1745}
1746
1748{
1749 //return true if doors are stopped
1750
1751 int start = number, end = number;
1752 if (number == 0)
1753 {
1754 start = 1;
1755 end = NumDoors;
1756 }
1757 for (int i = start; i <= end; i++)
1758 {
1759 ElevatorDoor *door = GetDoor(i);
1760 if (door)
1761 {
1762 if (door->DoorsStopped() == true)
1763 return true;
1764 }
1765 else
1766 ReportError("Invalid door " + ToString(i));
1767 }
1768 return false;
1769}
1770
1771int ElevatorCar::AreDoorsMoving(int number, bool car_doors, bool shaft_doors)
1772{
1773 //returns 1 if doors are opening (2 manual), -1 if doors are closing (-2 manual), or 0 if doors are not moving
1774 //if the type of door is specified, returns value if that type of door is moving
1775
1776 int start = number, end = number;
1777 if (number == 0)
1778 {
1779 start = 1;
1780 end = NumDoors;
1781 }
1782 for (int i = start; i <= end; i++)
1783 {
1784 ElevatorDoor *door = GetDoor(i);
1785 if (door)
1786 {
1787 if (door->AreDoorsMoving(0, car_doors, shaft_doors) == true)
1788 return door->OpenDoor;
1789 }
1790 else
1791 ReportError("Invalid door " + ToString(i));
1792 }
1793 return 0;
1794}
1795
1796bool ElevatorCar::AreDoorsOpening(int number, bool car_doors, bool shaft_doors)
1797{
1798 //returns true if doors are opening
1799
1800 if (AreDoorsMoving(number, car_doors, shaft_doors) == 1)
1801 return true;
1802 return false;
1803}
1804
1805bool ElevatorCar::AreDoorsClosing(int number, bool car_doors, bool shaft_doors)
1806{
1807 //returns true if doors are closing
1808
1809 if (AreDoorsMoving(number, car_doors, shaft_doors) == -1)
1810 return true;
1811 return false;
1812}
1813
1815{
1816 //enable/disable all doors
1817
1818 SBS_PROFILE("Elevator::EnableDoors");
1819 if (sbs->Verbose)
1820 {
1821 if (value == true)
1822 Report("enabling doors");
1823 else
1824 Report("disabling doors");
1825 }
1826
1827 for (int i = 1; i <= NumDoors; i++)
1828 {
1829 ElevatorDoor *door = GetDoor(i);
1830 if (door)
1831 door->Enabled(value);
1832 }
1833
1834 parent->DoorContainer->Enabled(value);
1835}
1836
1837void ElevatorCar::SetShaftDoors(int number, Real thickness, Real CenterX, Real CenterZ)
1838{
1839 int start = number, end = number;
1840 if (number == 0)
1841 {
1842 start = 1;
1843 end = NumDoors;
1844 }
1845 for (int i = start; i <= end; i++)
1846 {
1847 if (GetDoor(i))
1848 GetDoor(i)->SetShaftDoors(thickness, CenterX, CenterZ);
1849 else
1850 ReportError("Invalid door " + ToString(i));
1851 }
1852}
1853
1854bool 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)
1855{
1856 //adds floor signs at the specified position and direction for each serviced floor,
1857 //depending on if the given door number services the floor or not (unless door_number is 0)
1858
1859 Real x, z;
1860 if (relative == true)
1861 {
1862 x = GetPosition().x + CenterX;
1863 z = GetPosition().z + CenterZ;
1864 }
1865 else
1866 {
1867 x = CenterX;
1868 z = CenterZ;
1869 }
1870
1871 //make sure specified door exists before continuing
1872 if (door_number != 0)
1873 {
1874 if (DoorExists(door_number) == false)
1875 return ReportError("AddFloorSigns: door " + ToString(door_number) + " does not exist");
1876 }
1877
1878 bool autosize_x, autosize_y;
1879 sbs->GetTextureManager()->GetAutoSize(autosize_x, autosize_y);
1880 sbs->GetTextureManager()->SetAutoSize(false, false);
1881
1882 for (size_t i = 0; i < ServicedFloors.size(); i++)
1883 {
1884 bool door_result = false;
1885 int floor = ServicedFloors[i];
1886 Real base = GetDestinationOffset(floor);
1887
1888 if (door_number != 0)
1889 door_result = ShaftDoorsExist(door_number, floor);
1890
1891 if ((door_number == 0 || door_result == true) && sbs->GetFloor(floor))
1892 {
1893 std::string texture = texture_prefix + sbs->GetFloor(floor)->ID;
1894 std::string tmpdirection = direction;
1895 SetCase(tmpdirection, false);
1896
1897 if (tmpdirection == "front" || tmpdirection == "left")
1898 sbs->DrawWalls(true, false, false, false, false, false);
1899 else
1900 sbs->DrawWalls(false, true, false, false, false, false);
1901
1902 if (tmpdirection == "front" || tmpdirection == "back")
1903 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);
1904 else
1905 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);
1906 sbs->ResetWalls();
1907 }
1908 }
1909 sbs->GetTextureManager()->SetAutoSize(autosize_x, autosize_y);
1910 return true;
1911}
1912
1914{
1915 //check if the specified door exists
1916 //if number is 0, return true if any door exists
1917
1918 int start = number, end = number;
1919 if (number == 0)
1920 {
1921 start = 1;
1922 end = NumDoors;
1923 }
1924 for (int i = start; i <= end; i++)
1925 {
1926 if (GetDoor(i))
1927 return true;
1928 }
1929 return false;
1930}
1931
1932bool ElevatorCar::ShaftDoorsExist(int number, int floor, bool include_nonserviced)
1933{
1934 //return true if shaft doors exist on the specified floor
1935
1936 int start = number, end = number;
1937 if (number == 0)
1938 {
1939 start = 1;
1940 end = NumDoors;
1941 }
1942 for (int i = start; i <= end; i++)
1943 {
1944 ElevatorDoor *door = GetDoor(i);
1945 if (door)
1946 {
1947 if (door->ShaftDoorsExist(floor, include_nonserviced) == true)
1948 return true;
1949 }
1950 }
1951 return false;
1952}
1953
1954Sound* 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)
1955{
1956 //create a sound object
1957 Sound *sound = new Sound(this, name, false);
1958 sounds.emplace_back(sound);
1959
1960 //set parameters and play sound
1961 sound->Move(position);
1962 sound->SetDirection(direction);
1963 sound->SetVolume(volume);
1964 sound->SetSpeed(speed);
1965 sound->SetDistances(min_distance, max_distance);
1966 sound->SetDirection(direction);
1967 sound->SetDopplerLevel(doppler_level);
1968 sound->SetConeSettings(cone_inside_angle, cone_outside_angle, cone_outside_volume);
1969 sound->Load(filename);
1970 sound->SetLoopState(loop);
1971 if (loop && sbs->IsRunning == true && InCar() == true)
1972 sound->Play();
1973
1974 return sound;
1975}
1976
1978{
1979 //turn off button lights
1980 if (sbs->Verbose)
1981 Report("turning off button lights");
1982
1983 for (size_t i = 0; i < PanelArray.size(); i++)
1984 PanelArray[i]->ChangeAllLights(false);
1985}
1986
1987void ElevatorCar::ChangeLight(int floor, bool value)
1988{
1989 //turn on or off specified button lights
1990
1991 if (value == true)
1992 {
1993 if (sbs->Verbose)
1994 Report("turning on button lights for floor " + ToString(floor));
1995 }
1996 else
1997 {
1998 if (sbs->Verbose)
1999 Report("turning off button lights for floor " + ToString(floor));
2000 }
2001
2002 for (size_t i = 0; i < PanelArray.size(); i++)
2003 PanelArray[i]->ChangeLight(floor, value);
2004}
2005
2006DoorWrapper* 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)
2007{
2008 //adds an elevator door component to the specified door at a relative central position (off of elevator origin)
2009
2010 if (GetDoor(number))
2011 return GetDoor(number)->AddDoorComponent(name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
2012 else
2013 ReportError("Invalid door " + ToString(number));
2014 return 0;
2015}
2016
2017DoorWrapper* 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)
2018{
2019 //adds a single elevator shaft door component on the specified floor
2020
2021 if (IsServicedFloor(floor) == true && GetDoor(number))
2022 return GetDoor(number)->AddShaftDoorComponent(floor, name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
2023 else
2024 return 0;
2025}
2026
2027void 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)
2028{
2029 //adds shaft's elevator door components specified at a relative central position (off of elevator origin)
2030
2031 if (GetDoor(number))
2032 {
2033 Report("Adding shaft doors component...");
2034 GetDoor(number)->AddShaftDoorsComponent(name, texture, sidetexture, thickness, direction, OpenSpeed, CloseSpeed, x1, z1, x2, z2, height, voffset, tw, th, side_tw, side_th);
2035 }
2036 else
2037 ReportError("Invalid door " + ToString(number));
2038}
2039
2040DoorWrapper* ElevatorCar::FinishDoors(int number, bool DoorWalls, bool TrackWalls)
2041{
2042 //finishes elevator door
2043
2044 if (GetDoor(number))
2045 return GetDoor(number)->FinishDoors(DoorWalls, TrackWalls);
2046 else
2047 ReportError("Invalid door " + ToString(number));
2048 return 0;
2049}
2050
2051DoorWrapper* ElevatorCar::FinishShaftDoor(int number, int floor, bool DoorWalls, bool TrackWalls)
2052{
2053 //finishes a single shaft door
2054
2055 if (IsServicedFloor(floor) == true && GetDoor(number))
2056 return GetDoor(number)->FinishShaftDoor(floor, DoorWalls, TrackWalls);
2057 else
2058 return 0;
2059}
2060
2061bool ElevatorCar::FinishShaftDoors(int number, bool DoorWalls, bool TrackWalls)
2062{
2063 //finishes all shaft doors
2064
2065 if (GetDoor(number))
2066 return GetDoor(number)->FinishShaftDoors(DoorWalls, TrackWalls);
2067 else
2068 ReportError("Invalid door " + ToString(number));
2069 return false;
2070}
2071
2073{
2074 //get a button panel object
2075
2076 if (index > (int)PanelArray.size() || index < 1)
2077 return 0;
2078
2079 return PanelArray[index - 1];
2080}
2081
2083{
2084 //get a floor button
2085
2086 if (parent->Running == false)
2087 {
2088 ReportError("Elevator not running");
2089 return 0;
2090 }
2091
2092 if (PanelArray.empty() == false)
2093 {
2094 for (size_t i = 0; i < PanelArray.size(); i++)
2095 {
2096 Control *control = PanelArray[i]->GetFloorButton(floor);
2097 if (control)
2098 return control;
2099 }
2100 }
2101 return 0;
2102}
2103
2104void ElevatorCar::HoldDoors(int number, bool sensor)
2105{
2106 //hold specified door, or all if "0" is given
2107
2108 int start = number, end = number;
2109 if (number == 0)
2110 {
2111 start = 1;
2112 end = NumDoors;
2113 }
2114 for (int i = start; i <= end; i++)
2115 {
2116 if (GetDoor(i))
2117 GetDoor(i)->Hold(sensor);
2118 else
2119 ReportError("Invalid door " + ToString(i));
2120 }
2121}
2122
2123Door* 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)
2124{
2125 //interface to the SBS AddDoor function
2126
2127 //set up coordinates
2128 /*Real x1, z1, x2, z2;
2129 if (face_direction == "left" || face_direction == "right")
2130 {
2131 x1 = CenterX;
2132 x2 = CenterX;
2133 z1 = CenterZ - (width / 2);
2134 z2 = CenterZ + (width / 2);
2135 }
2136 else
2137 {
2138 x1 = CenterX - (width / 2);
2139 x2 = CenterX + (width / 2);
2140 z1 = CenterZ;
2141 z2 = CenterZ;
2142 }
2143
2144 //cut area
2145 if (face_direction == "left" || face_direction == "right")
2146 CutAll(Vector3(x1 - 1, GetBase(true) + voffset, z1), Vector3(x2 + 1, GetBase(true) + voffset + height, z2), true, false);
2147 else
2148 CutAll(Vector3(x1, GetBase(true) + voffset, z1 - 1), Vector3(x2, GetBase(true) + voffset + height, z2 + 1), true, false);
2149 */
2150
2151 std::string number = ToString((int)StdDoorArray.size());
2152 if (name == "")
2153 name = "Door " + number;
2154
2155 Door* door = new Door(this, 0, name, open_sound, close_sound, rotate);
2156 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);
2157 StdDoorArray.emplace_back(door);
2158 return door;
2159}
2160
2161Door* ElevatorCar::CreateDoor(std::string name, const std::string &open_sound, const std::string &close_sound, bool rotate)
2162{
2163 //start creation of a manual door
2164 //since the door is unfinished, AddDoorComponent and FinishDoor need to be run on the returned Door object
2165
2166 std::string number = ToString((int)StdDoorArray.size());
2167 if (name == "")
2168 name = "Door " + number;
2169
2170 Door* door = new Door(this, 0, name, open_sound, close_sound, rotate);
2171 StdDoorArray.emplace_back(door);
2172 return door;
2173}
2174
2176{
2177 //get door object
2178 if (number < (int)StdDoorArray.size())
2179 {
2180 if (StdDoorArray[number])
2181 return StdDoorArray[number];
2182 }
2183
2184 return 0;
2185}
2186
2187Door* ElevatorCar::GetDoor(const std::string &name)
2188{
2189 for (size_t i = 0; i < StdDoorArray.size(); i++)
2190 {
2191 if (StdDoorArray[i]->GetName() == name)
2192 return StdDoorArray[i];
2193 }
2194 return 0;
2195}
2196
2198{
2199 //remove a button panel reference (does not delete the object itself)
2200 for (size_t i = 0; i < PanelArray.size(); i++)
2201 {
2202 if (PanelArray[i] == panel)
2203 {
2204 PanelArray.erase(PanelArray.begin() + i);
2205 return;
2206 }
2207 }
2208}
2209
2211{
2212 //remove a directional indicator reference (does not delete the object itself)
2213 for (size_t i = 0; i < DirIndicatorArray.size(); i++)
2214 {
2215 if (DirIndicatorArray[i] == indicator)
2216 {
2217 DirIndicatorArray.erase(DirIndicatorArray.begin() + i);
2218 return;
2219 }
2220 }
2221}
2222
2224{
2225 //remove an elevator door reference (does not delete the object itself)
2226 for (size_t i = 0; i < DoorArray.size(); i++)
2227 {
2228 if (DoorArray[i] == door)
2229 {
2230 DoorArray.erase(DoorArray.begin() + i);
2231 NumDoors--;
2232
2233 //reset cache values
2234 lastdoor_number = 0;
2235 lastdoor_result = 0;
2236 return;
2237 }
2238 }
2239}
2240
2242{
2243 //remove a floor indicator reference (does not delete the object itself)
2244 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
2245 {
2247 {
2248 FloorIndicatorArray.erase(FloorIndicatorArray.begin() + i);
2249 return;
2250 }
2251 }
2252}
2253
2255{
2256 //remove a door reference (does not delete the object itself)
2257 for (size_t i = 0; i < StdDoorArray.size(); i++)
2258 {
2259 if (StdDoorArray[i] == door)
2260 {
2261 StdDoorArray.erase(StdDoorArray.begin() + i);
2262 return;
2263 }
2264 }
2265}
2266
2268{
2269 //remove a sound reference (does not delete the object itself)
2270 for (size_t i = 0; i < sounds.size(); i++)
2271 {
2272 if (sounds[i] == sound)
2273 {
2274 sounds.erase(sounds.begin() + i);
2275 return;
2276 }
2277 }
2278}
2279
2281{
2282 //remove a light reference (does not delete the object itself)
2283 for (size_t i = 0; i < lights.size(); i++)
2284 {
2285 if (lights[i] == light)
2286 {
2287 lights.erase(lights.begin() + i);
2288 return;
2289 }
2290 }
2291}
2292
2294{
2295 //remove a model reference (does not delete the object itself)
2296 for (size_t i = 0; i < ModelArray.size(); i++)
2297 {
2298 if (ModelArray[i] == model)
2299 {
2300 ModelArray.erase(ModelArray.begin() + i);
2301 return;
2302 }
2303 }
2304}
2305
2307{
2308 //remove a prim reference (does not delete the object itself)
2309 for (size_t i = 0; i < PrimArray.size(); i++)
2310 {
2311 if (PrimArray[i] == prim)
2312 {
2313 PrimArray.erase(PrimArray.begin() + i);
2314 return;
2315 }
2316 }
2317}
2318
2320{
2321 //remove a custom object reference (does not delete the object itself)
2322 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2323 {
2324 if (CustomObjectArray[i] == object)
2325 {
2326 CustomObjectArray.erase(CustomObjectArray.begin() + i);
2327 return;
2328 }
2329 }
2330}
2331
2333{
2334 //remove a control reference (does not delete the object itself)
2335 for (size_t i = 0; i < ControlArray.size(); i++)
2336 {
2337 if (ControlArray[i] == control)
2338 {
2339 ControlArray.erase(ControlArray.begin() + i);
2340 return;
2341 }
2342 }
2343}
2344
2346{
2347 //remove a trigger reference (does not delete the object itself)
2348 for (size_t i = 0; i < TriggerArray.size(); i++)
2349 {
2350 if (TriggerArray[i] == trigger)
2351 {
2352 TriggerArray.erase(TriggerArray.begin() + i);
2353 return;
2354 }
2355 }
2356}
2357
2359{
2360 //checks doors and returns true if any (or the specified door) have nudge mode active
2361
2362 int start = number, end = number;
2363 if (number == 0)
2364 {
2365 start = 1;
2366 end = NumDoors;
2367 }
2368 for (int i = start; i <= end; i++)
2369 {
2370 ElevatorDoor *door = GetDoor(i);
2371 if (door)
2372 {
2373 if (door->GetNudgeStatus() == true)
2374 return true;
2375 }
2376 else
2377 ReportError("Invalid door " + ToString(i));
2378 }
2379
2380 return false;
2381}
2382
2383void ElevatorCar::EnableNudgeMode(bool value, int number)
2384{
2385 //enables nudge mode on all doors or the specified door
2386
2387 //only run if power is enabled
2388 if (sbs->GetPower() == false)
2389 return;
2390
2391 int start = number, end = number;
2392 if (number == 0)
2393 {
2394 start = 1;
2395 end = NumDoors;
2396 }
2397 for (int i = start; i <= end; i++)
2398 {
2399 ElevatorDoor *door = GetDoor(i);
2400 if (door)
2401 door->EnableNudgeMode(value);
2402 else
2403 ReportError("Invalid door " + ToString(i));
2404 }
2405}
2406
2407void ElevatorCar::ResetNudgeTimer(bool start, int number)
2408{
2409 //resets and optionally starts nudge timer on the specified door
2410
2411 int start2 = number, end = number;
2412 if (number == 0)
2413 {
2414 start2 = 1;
2415 end = NumDoors;
2416 }
2417 for (int i = start2; i <= end; i++)
2418 {
2419 ElevatorDoor *door = GetDoor(i);
2420 if (door)
2421 {
2422 door->ResetNudgeTimer(start);
2423 }
2424 else
2425 ReportError("Invalid door " + ToString(i));
2426 }
2427}
2428
2429Light* ElevatorCar::AddLight(const std::string &name, int type)
2430{
2431 //add a global light
2432
2433 Light* light = new Light(this, name, type);
2434 lights.emplace_back(light);
2435 light->Enabled(false);
2436 return light;
2437}
2438
2439Light* ElevatorCar::GetLight(const std::string &name)
2440{
2441 for (size_t i = 0; i < lights.size(); i++)
2442 {
2443 if (lights[i]->GetName() == name)
2444 return lights[i];
2445 }
2446 return 0;
2447}
2448
2449Model* 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)
2450{
2451 //add a model
2452 Model* model = new Model(this, name, filename, center, position, rotation, max_render_distance, scale_multiplier, enable_physics, restitution, friction, mass);
2453 if (model->load_error == true)
2454 {
2455 delete model;
2456 return 0;
2457 }
2458 ModelArray.emplace_back(model);
2459 return model;
2460}
2461
2463{
2464 //add a model reference
2465
2466 if (!model)
2467 return;
2468
2469 for (size_t i = 0; i < ModelArray.size(); i++)
2470 {
2471 if (ModelArray[i] == model)
2472 return;
2473 }
2474
2475 ModelArray.emplace_back(model);
2476}
2477
2478Primitive* ElevatorCar::AddPrimitive(const std::string &name)
2479{
2480 //add a prim
2481 Primitive* prim = new Primitive(this, name);
2482 PrimArray.emplace_back(prim);
2483 return prim;
2484}
2485
2487{
2488 //add a model reference
2489
2490 if (!primitive)
2491 return;
2492
2493 for (size_t i = 0; i < PrimArray.size(); i++)
2494 {
2495 if (PrimArray[i] == primitive)
2496 return;
2497 }
2498
2499 PrimArray.emplace_back(primitive);
2500}
2501
2502CustomObject* ElevatorCar::AddCustomObject(const std::string &name, const Vector3 &position, const Vector3 &rotation, Real max_render_distance, Real scale_multiplier)
2503{
2504 //add a custom object
2505 CustomObject* object = new CustomObject(this, name, position, rotation, max_render_distance, scale_multiplier);
2506 CustomObjectArray.emplace_back(object);
2507 return object;
2508}
2509
2511{
2512 //add a custom object reference
2513
2514 if (!object)
2515 return;
2516
2517 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2518 {
2519 if (CustomObjectArray[i] == object)
2520 return;
2521 }
2522
2523 CustomObjectArray.emplace_back(object);
2524}
2525
2527{
2528 //add a floor to the display floors list
2529 DisplayFloors.emplace_back(floor);
2530}
2531
2533{
2534 //returns the current floor's indicator display string
2535
2536 //only run if power is enabled
2537 if (sbs->GetPower() == false)
2538 return "";
2539
2540 std::string value;
2541 int floornum = GetFloor();
2542 Floor *floor = sbs->GetFloor(floornum);
2543
2544 if (!floor)
2545 return value;
2546
2547 //only show floor skip text if the floor is not serviced by any car in this elevator
2548 if (parent->UseFloorSkipText == true && IsServicedFloor(floornum) == false && parent->IsServicedFloor(floornum) == false)
2549 value = parent->FloorSkipText;
2550 else
2551 {
2552 if (DisplayFloors.size() > 0)
2553 {
2554 for (size_t i = 0; i < DisplayFloors.size(); i++)
2555 {
2556 if (floornum == DisplayFloors[i])
2557 {
2558 value = floor->ID;
2559 break;
2560 }
2561 }
2562 }
2563 else
2564 value = floor->ID;
2565 }
2566 return value;
2567}
2568
2569Control* 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)
2570{
2571 //add a control
2572 std::vector<Action*> actionnull; //not used
2573 Control* control = new Control(this, name, false, sound, action_names, actionnull, textures, direction, width, height, true, selection_position);
2574 control->Move(Vector3(CenterX, voffset, CenterZ));
2575 ControlArray.emplace_back(control);
2576 return control;
2577}
2578
2579Trigger* ElevatorCar::AddTrigger(const std::string &name, const std::string &sound_file, Vector3 &area_min, Vector3 &area_max, std::vector<std::string> &action_names)
2580{
2581 //add a trigger
2582 Trigger* trigger = new Trigger(this, name, false, sound_file, area_min, area_max, action_names);
2583 TriggerArray.emplace_back(trigger);
2584 return trigger;
2585}
2586
2587bool ElevatorCar::ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
2588{
2589 return Mesh->ReplaceTexture(oldtexture, newtexture);
2590}
2591
2592std::vector<Sound*> ElevatorCar::GetSound(const std::string &name)
2593{
2594 //get sound by name
2595
2596 std::string findname = name;
2597 SetCase(findname, false);
2598 std::vector<Sound*> soundlist;
2599 for (size_t i = 0; i < sounds.size(); i++)
2600 {
2601 if (sounds[i])
2602 {
2603 std::string name2 = sounds[i]->GetName();
2604 SetCase(name2, false);
2605 if (findname == name2)
2606 soundlist.emplace_back(sounds[i]);
2607 }
2608 }
2609 return soundlist;
2610}
2611
2613{
2614 //checks doors and returns true if any (or the specified door) have their door sensor active
2615
2616 int start = number, end = number;
2617 if (number == 0)
2618 {
2619 start = 1;
2620 end = NumDoors;
2621 }
2622 for (int i = start; i <= end; i++)
2623 {
2624 ElevatorDoor *door = GetDoor(i);
2625 if (door)
2626 {
2627 if (door->GetSensorStatus() == true)
2628 return true;
2629 }
2630 else
2631 ReportError("Invalid door " + ToString(i));
2632 }
2633
2634 return false;
2635}
2636
2637void ElevatorCar::EnableSensor(bool value, int number)
2638{
2639 //enables door sensor on all doors or the specified door
2640
2641 //only run if power is enabled
2642 if (sbs->GetPower() == false)
2643 return;
2644
2645 int start = number, end = number;
2646 if (number == 0)
2647 {
2648 start = 1;
2649 end = NumDoors;
2650 }
2651 for (int i = start; i <= end; i++)
2652 {
2653 ElevatorDoor *door = GetDoor(i);
2654 if (door)
2655 door->EnableSensor(value);
2656 else
2657 ReportError("Invalid door " + ToString(i));
2658 }
2659}
2660
2662{
2663 //checks doors and returns true if any (or the specified door) have door hold enabled
2664
2665 int start = number, end = number;
2666 if (number == 0)
2667 {
2668 start = 1;
2669 end = NumDoors;
2670 }
2671 for (int i = start; i <= end; i++)
2672 {
2673 ElevatorDoor *door = GetDoor(i);
2674 if (door)
2675 {
2676 if (door->GetHoldStatus() == true)
2677 return true;
2678 }
2679 else
2680 ReportError("Invalid door " + ToString(i));
2681 }
2682
2683 return false;
2684}
2685
2687{
2688 //reset elevator internal door state, in case of door malfunction
2689
2690 //only run if power is enabled
2691 if (sbs->GetPower() == false)
2692 return;
2693
2694 int start = number, end = number;
2695 if (number == 0)
2696 {
2697 start = 1;
2698 end = NumDoors;
2699 }
2700 for (int i = start; i <= end; i++)
2701 {
2702 ElevatorDoor *door = GetDoor(i);
2703 if (door)
2704 door->ResetState();
2705 else
2706 ReportError("Invalid door " + ToString(i));
2707 }
2708}
2709
2711{
2712 //get a model by name
2713
2714 SetCase(name, false);
2715
2716 for (size_t i = 0; i < ModelArray.size(); i++)
2717 {
2718 if (SetCaseCopy(ModelArray[i]->GetName(), false) == name)
2719 return ModelArray[i];
2720 }
2721
2722 return 0;
2723}
2724
2726{
2727 //get a primitive by name
2728
2729 SetCase(name, false);
2730
2731 for (size_t i = 0; i < PrimArray.size(); i++)
2732 {
2733 if (SetCaseCopy(PrimArray[i]->GetName(), false) == name)
2734 return PrimArray[i];
2735 }
2736
2737 return 0;
2738}
2739
2741{
2742 //get a custom object by name
2743
2744 SetCase(name, false);
2745
2746 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2747 {
2748 if (SetCaseCopy(CustomObjectArray[i]->GetName(), false) == name)
2749 return CustomObjectArray[i];
2750 }
2751
2752 return 0;
2753}
2754
2755void ElevatorCar::SetBeepSound(const std::string &filename)
2756{
2757 //set sound used for floor beeps
2758 if (sbs->Verbose)
2759 Report("setting beep sound");
2760 BeepSound = filename;
2762 UseFloorBeeps = true;
2763}
2764
2765void ElevatorCar::SetFloorSound(const std::string &prefix)
2766{
2767 //set prefix of floor sound
2768 if (sbs->Verbose)
2769 Report("setting floor sound");
2770 FloorSound = prefix;
2772 UseFloorSounds = true;
2773}
2774
2775void ElevatorCar::SetMessageSound(bool type, bool direction, const std::string &filename)
2776{
2777 //if type is true, sets up and down messages. If false, sets open and close messages
2778 //if direction is true, set up message sound; otherwise set down message sound
2779
2780 if (type == true)
2781 {
2782 if (direction == true)
2783 {
2784 if (sbs->Verbose)
2785 Report("setting up message sound");
2786 UpMessageSound = filename;
2788 }
2789 else
2790 {
2791 if (sbs->Verbose)
2792 Report("setting down message sound");
2793 DownMessageSound = filename;
2795 }
2796 UseDirMessageSounds = true;
2797 }
2798 else
2799 {
2800 if (direction == true)
2801 {
2802 if (sbs->Verbose)
2803 Report("setting open message sound");
2804 OpenMessageSound = filename;
2806 }
2807 else
2808 {
2809 if (sbs->Verbose)
2810 Report("setting close message sound");
2811 CloseMessageSound = filename;
2813 }
2814 UseDoorMessageSounds = true;
2815 }
2816}
2817
2819{
2820 //play floor beep sound
2821
2822 //only run if power is enabled
2823 if (sbs->GetPower() == false)
2824 return false;
2825
2826 if (parent->InServiceMode() == true || BeepSound == "" || UseFloorBeeps == false)
2827 return false;
2828
2829 if (sbs->Verbose)
2830 Report("playing floor beep sound");
2831
2832 std::string newsound = BeepSound;
2833 //change the asterisk into the current floor number
2834 ReplaceAll(newsound, "*", ToString(GetFloor()));
2835 TrimString(newsound);
2836 floorbeep->Stop();
2837 floorbeep->Load(newsound);
2838 floorbeep->SetLoopState(false);
2839 floorbeep->Play();
2840 return true;
2841}
2842
2844{
2845 //play floor sound
2846
2847 //only run if power is enabled
2848 if (sbs->GetPower() == false)
2849 return false;
2850
2851 if (parent->InServiceMode() == true || FloorSound == "" || UseFloorSounds == false || parent->SkipFloorSound == true)
2852 return false;
2853
2854 if (sbs->Verbose)
2855 Report("playing floor sound");
2856
2857 std::string newsound = FloorSound;
2858 //change the asterisk into the current floor number
2859 ReplaceAll(newsound, "*", ToString(parent->GotoFloor));
2860 TrimString(newsound);
2861 announcesnd->PlayQueued(newsound, false, false);
2862 return true;
2863}
2864
2866{
2867 //play message sound
2868 //if type is true, play directional up/down sounds, otherwise play door open/close sounds
2869 //if direction is true, play up sound; otherwise play down sound
2870
2871 //only run if power is enabled
2872 if (sbs->GetPower() == false)
2873 return false;
2874
2875 if (parent->InServiceMode() == true)
2876 return false;
2877
2878 if (parent->IsQueueActive() == false && type == true && MessageOnClose == true)
2879 return false;
2880
2881 std::string newsound;
2882
2883 if (type == true)
2884 {
2885 //exit if directional message sounds are off, or one has already been queued
2886 if (UseDirMessageSounds == false || DirMessageSound == true)
2887 return false;
2888
2889 int direction = 0;
2890
2891 if (MessageOnMove == false)
2892 {
2893 if (parent->LastChimeDirection == 0)
2894 return false;
2895
2896 if (parent->NotifyLate == false && parent->NotifyEarly == -1)
2897 return false;
2898
2899 direction = parent->LastChimeDirection;
2900
2901 //if (parent->LastChimeDirection == 0)
2902 //direction = parent->GetRouteController()->LastQueueDirection;
2903 }
2904 else
2905 direction = parent->ActiveDirection;
2906
2907 if (direction == 1)
2908 {
2909 if (UpMessageSound == "")
2910 return false;
2911
2912 if (sbs->Verbose)
2913 Report("playing up message sound");
2914
2915 newsound = UpMessageSound;
2916 }
2917 else
2918 {
2919 if (DownMessageSound == "")
2920 return false;
2921
2922 if (sbs->Verbose)
2923 Report("playing down message sound");
2924
2925 newsound = DownMessageSound;
2926 }
2927
2928 DirMessageSound = true;
2929 }
2930 else
2931 {
2932 //exit if door message sounds are off, or one has already been queued
2933 if (UseDoorMessageSounds == false || DoorMessageSound == true)
2934 return false;
2935
2936 if (AreDoorsOpening() == true)
2937 {
2938 if (OpenMessageSound == "")
2939 return false;
2940
2941 if (sbs->Verbose)
2942 Report("playing open message sound");
2943
2944 newsound = OpenMessageSound;
2945 }
2946 else if (AreDoorsClosing() == true)
2947 {
2948 if (CloseMessageSound == "")
2949 return false;
2950
2951 if (sbs->Verbose)
2952 Report("playing close message sound");
2953
2954 newsound = CloseMessageSound;
2955 }
2956 else
2957 return false;
2958
2959 DoorMessageSound = true;
2960 }
2961
2962 //change the asterisk into the current floor number
2963 ReplaceAll(newsound, "*", ToString(GetFloor()));
2964 TrimString(newsound);
2965 announcesnd->PlayQueued(newsound, false, false);
2966 return true;
2967}
2968
2970{
2971 //play car starting sounds
2972
2973 carsound->Stop();
2974 if (parent->Direction == 1 && UpStartSound.empty() == false && UpStartSound != "")
2975 {
2976 if (sbs->Verbose)
2977 Report("playing car up start sound");
2978
2980 carsound->SetLoopState(false);
2981 carsound->Play();
2982 }
2983 if (parent->Direction == -1 && DownStartSound.empty() == false && DownStartSound != "")
2984 {
2985 if (sbs->Verbose)
2986 Report("playing car down start sound");
2987
2989 carsound->SetLoopState(false);
2990 carsound->Play();
2991 }
2992}
2993
2995{
2996 //play car stopping sounds
2997 //if emergency is true, plays emergency stop sounds with a fallback to standard sounds
2998
2999 bool play = false;
3000 std::string file;
3001
3002 if (emergency == true)
3003 {
3004 if (EmergencyStopSound.empty() == false && EmergencyStopSound != "")
3005 {
3006 if (sbs->Verbose)
3007 Report("playing car emergency stop sound");
3008
3009 file = EmergencyStopSound;
3010 play = true;
3011 }
3012 }
3013
3014 if (play == false)
3015 {
3016 if (parent->Direction == -1 && UpStopSound.empty() == false && UpStopSound != "")
3017 {
3018 if (sbs->Verbose)
3019 Report("playing car up stop sound");
3020
3021 file = UpStopSound;
3022 play = true;
3023 }
3024 if (parent->Direction == 1 && DownStopSound.empty() == false && DownStopSound != "")
3025 {
3026 if (sbs->Verbose)
3027 Report("playing car down stop sound");
3028
3029 file = DownStopSound;
3030 play = true;
3031 }
3032 }
3033
3034 carsound->Stop();
3035
3036 if (play == true)
3037 {
3038 carsound->Load(file);
3039 carsound->SetLoopState(false);
3040
3041 //set play position to current percent of the total speed
3042 if (parent->AutoAdjustSound == true)
3043 {
3044 if (parent->Direction == 1)
3046 else
3048 }
3049 else
3050 carsound->Reset();
3051
3052 carsound->Play(false);
3053 }
3054}
3055
3057{
3058 //play car movement sounds
3059
3060 if (carsound->IsPlaying() == false)
3061 {
3062 if (parent->Direction == 1 && UpMoveSound.empty() == false && UpMoveSound != "")
3063 {
3064 if (sbs->Verbose)
3065 Report("playing car up movement sound");
3066
3068 carsound->SetLoopState(true);
3069 carsound->Play();
3070 }
3071 else if (parent->Direction == -1 && DownMoveSound.empty() == false && DownMoveSound != "")
3072 {
3073 if (sbs->Verbose)
3074 Report("playing car down movement sound");
3075
3077 carsound->SetLoopState(true);
3078 carsound->Play();
3079 }
3080 }
3081}
3082
3084{
3085 //make sure height value is set
3086 if (HeightSet == false)
3087 {
3088 Height = Mesh->GetHeight();
3089 HeightSet = true;
3090
3091 //position sounds at top of elevator car
3092 Vector3 top = Vector3(0, Height, 0);
3093 idlesound->SetPosition(top, true);
3094 alarm->SetPosition(top, true);
3095 floorbeep->SetPosition(top, true);
3096 announcesnd->SetPosition(top, true);
3097
3098 //set default music position to elevator height
3099 if (MusicPosition == Vector3(0, 0, 0) && Height > 0)
3100 MusicPosition = top;
3102 }
3103
3104 return Height;
3105}
3106
3107bool ElevatorCar::IsInCar(const Vector3 &position, bool camera)
3108{
3109 //determine if the given 3D position is inside the car
3110
3111 //first checks to see if camera is within an car height range, and then
3112 //checks for a collision with the car floor below
3113
3114 //if camera is true, set associated camera offset
3115
3116 //SBS_PROFILE("ElevatorCar::IsInCar");
3117 bool result = false;
3118
3119 if (IsEnabled == false)
3120 return false;
3121
3122 //if last position is the same as new, return previous result
3123 if (position.positionEquals(lastposition) == true && checkfirstrun == false)
3124 return lastcheckresult;
3125
3126 checkfirstrun = false;
3127
3128 Real ypos = GetPosition().y;
3129
3130 if (position.y >= (ypos - 0.1) && position.y < ypos + (Height * 2))
3131 {
3132 if (Mesh->InBoundingBox(position, false) == true)
3133 {
3134 if (Mesh->HitBeam(position, Vector3::NEGATIVE_UNIT_Y, Height) >= 0)
3135 {
3136 if (camera == true)
3137 CameraOffset = position.y - ypos;
3138 result = true;
3139 }
3140 }
3141 else if (camera == true)
3142 CameraOffset = 0;
3143
3144 if (position.y < ypos + Height)
3145 {
3146 //cache values
3147 lastcheckresult = result;
3148 lastposition = position;
3149
3150 return result;
3151 }
3152 }
3153 else if (camera == true)
3154 CameraOffset = 0;
3155
3156 //cache values
3157 lastcheckresult = false;
3158 lastposition = position;
3159
3160 return false;
3161}
3162
3164{
3165 //check to see if user (camera) is in the car
3166
3167 if (IsEnabled == false)
3168 return false;
3169
3170 //SBS_PROFILE("ElevatorCar::Check");
3171
3172 if (IsInCar(position, true) == true && IsEnabled)
3173 {
3174 if (InCar() == false)
3175 {
3176 //turn on objects if moving into the car
3177 EnableObjects(true);
3179 }
3180 sbs->InElevator = true;
3182 sbs->CarNumber = Number;
3183 sbs->ElevatorSync = true;
3184 return true;
3185 }
3186
3187 //turn off objects if user has moved outside the car
3188 else if (InCar() == true)
3189 {
3190 EnableObjects(false);
3191 }
3192
3193 //if camera is within vertical elevator range, turn on syncing to allow things like elevator surfing
3194 else if (CameraOffset > Height && CameraOffset < Height * 2)
3195 {
3197 sbs->CarNumber = Number;
3198 sbs->ElevatorSync = true;
3199 return true;
3200 }
3201 return false;
3202}
3203
3205{
3206 //stop car sound
3207
3208 carsound->Stop();
3209}
3210
3212{
3213 //Determine floor that the car is on
3214
3215 int newlastfloor;
3216
3217 if (lastfloorset == true)
3218 newlastfloor = sbs->GetFloorNumber(GetPosition().y, lastfloor, true);
3219 else
3220 newlastfloor = sbs->GetFloorNumber(GetPosition().y);
3221
3222 lastfloor = newlastfloor;
3223 lastfloorset = true;
3224 return lastfloor;
3225}
3226
3228{
3229 //returns true if car is on the highest serviced floor
3230
3231 return (GetFloor() == GetTopFloor());
3232}
3233
3235{
3236 //returns true if car is on the lowest serviced floor
3237
3238 return (GetFloor() == GetBottomFloor());
3239}
3240
3242{
3243 //return true if user is currently in car
3244
3245 return (sbs->InElevator == true && sbs->ElevatorNumber == parent->Number && sbs->CarNumber == Number);
3246}
3247
3249{
3250 //return number of closest serviced floor
3251
3252 //only run if power is enabled
3253 if (sbs->GetPower() == false)
3254 return 0;
3255
3256 if (IsServicedFloor(GetFloor()) == true)
3257 return GetFloor();
3258
3259 if (ServicedFloors.size() == 0)
3260 return 0;
3261
3262 bool firstrun = true;
3263 size_t nearest = 0;
3264 Real nearest_difference = 0;
3265
3266 for (size_t i = 0; i < ServicedFloors.size() - 1; i++)
3267 {
3268 if (firstrun == true)
3269 {
3270 if (sbs->GetFloor(ServicedFloors[i]))
3271 {
3272 nearest_difference = std::abs(GetPosition().y - GetDestinationOffset(ServicedFloors[i]));
3273 nearest = i;
3274 firstrun = false;
3275 }
3276 }
3277 else
3278 {
3279 if (sbs->GetFloor(ServicedFloors[i]))
3280 {
3281 Real difference = std::abs(GetPosition().y - GetDestinationOffset(ServicedFloors[i]));
3282 if (difference < nearest_difference)
3283 {
3284 //mark closest
3285 nearest_difference = difference;
3286 nearest = i;
3287 }
3288 }
3289 }
3290 }
3291
3292 return ServicedFloors[nearest];
3293}
3294
3296{
3297 //returns the destination altitude of the specified floor, based on shaft door positioning
3298
3299 if (IsServicedFloor(floor) == false)
3300 return 0.0;
3301
3302 Real result = 0;
3303 bool found = false;
3304 for (size_t i = 0; i < DoorArray.size(); i++)
3305 {
3306 if (DoorArray[i]->ShaftDoorsExist(floor) == true)
3307 {
3308 Real altitude = DoorArray[i]->GetShaftDoorAltitude(floor);
3309
3310 if (altitude > result || found == false)
3311 {
3312 result = altitude;
3313 found = true;
3314 }
3315 }
3316 }
3317
3318 if (found == false)
3319 {
3320 if (sbs->GetFloor(floor))
3321 return sbs->GetFloor(floor)->GetBase();
3322 }
3323 return result;
3324}
3325
3327{
3328 //returns the offset distance from the floor's base altitude the elevator destination is
3329
3330 if (IsServicedFloor(floor) == false)
3331 return 0.0;
3332
3333 if (sbs->GetFloor(floor))
3334 return GetDestinationAltitude(floor) - sbs->GetFloor(floor)->GetBase();
3335
3336 return 0.0;
3337}
3338
3339void ElevatorCar::SetFloor(int floor, bool move_parent)
3340{
3341 //set car's altitude to specified floor
3342
3343 Real altitude = 0;
3344 if (!sbs->GetFloor(floor))
3345 return;
3346
3347 altitude = GetDestinationAltitude(floor);
3348 if (move_parent == true)
3349 {
3350 //move elevator, and any other cars
3351 parent->MoveObjects(altitude - parent->GetPosition().y);
3352 }
3353 else
3354 {
3355 //move just this car
3356 Vector3 vector (0, altitude - GetPosition().y, 0);
3357 Move(vector);
3358 }
3359}
3360
3362{
3363 //return true if car is leveled at a serviced floor
3364
3365 Real tolerance = 0.005;
3366
3367 int floor = GetFloor();
3368 if (IsServicedFloor(floor) == true)
3369 {
3370 Real altitude = GetDestinationAltitude(floor);
3371
3372 if (GetPosition().y >= altitude - tolerance &&
3373 GetPosition().y <= altitude + tolerance)
3374 return true;
3375 }
3376 return false;
3377}
3378
3379bool ElevatorCar::IsOnFloor(int floor, bool leveled)
3380{
3381 //return true if the car is on the specified floor
3382 //if leveled is true, returns true only if the car is leveled on that floor
3383
3384 if (GetFloor() == floor)
3385 {
3386 if (leveled == false)
3387 return true;
3388 else if (IsLeveled() == true && parent->IsMoving == false)
3389 return true;
3390 }
3391
3392 return false;
3393}
3394
3395void ElevatorCar::NotifyArrival(int floor, bool early, int direction)
3396{
3397 //notify on car arrival (play chime and turn on related directional indicator lantern)
3398
3399 //only run if power is enabled
3400 if (sbs->GetPower() == false)
3401 return;
3402
3403 //do not notify if in a service mode
3404 if (parent->InServiceMode() == true)
3405 return;
3406
3407 //get call button status
3408 bool up = true, down = true;
3409
3410 //if ChimeOnArrival is off, only chime if responding to a hall call
3411 if (parent->ChimeOnArrival == false && direction == 0)
3412 {
3413 //get call status from controller
3414 parent->GetCallStatus(floor, up, down);
3415
3416 //in DD mode, set direction to be the call response direction
3417 if (parent->GetDestinationDispatch() == true)
3418 direction = RespondingToCall(floor);
3419 }
3420
3421 bool new_direction = false;
3422
3423 //get notification direction
3424 if (LateDirection != 0)
3425 {
3426 //notify is a late notification
3427 if (LateDirection == 1)
3428 new_direction = true;
3429 else
3430 new_direction = false;
3431 LateDirection = 0;
3432 }
3433 else
3434 {
3435 if (direction == 0)
3436 {
3437 //notify is for a standard arrival
3438 new_direction = parent->GetArrivalDirection(floor);
3439 }
3440 else
3441 {
3442 //notify is for a same-floor call
3443 if (direction == 1)
3444 new_direction = true;
3445 else
3446 new_direction = false;
3447 }
3448 }
3449
3450 //play chime sound and change indicator
3451 if (new_direction == true)
3452 {
3453 if (up == true || direction == 1 || parent->NotifyLate == true || (parent->GetDestinationDispatch() == true && parent->ChimeOnArrival == true))
3454 {
3455 Chime(0, floor, true, early);
3456 SetDirectionalIndicators(floor, true, false);
3457 }
3459 }
3460 else
3461 {
3462 if (down == true || direction == -1 || parent->NotifyLate == true || (parent->GetDestinationDispatch() == true && parent->ChimeOnArrival == true))
3463 {
3464 Chime(0, floor, false, early);
3465 SetDirectionalIndicators(floor, false, true);
3466 }
3468 }
3469
3470 //play floor sound
3471 if (parent->FireServicePhase1 == 0 && parent->FireServicePhase2 == 0 && direction == 0)
3473}
3474
3476{
3477 //returns true if independent service mode is active for this car
3478
3480}
3481
3483{
3484 //returns true if independent service mode is active on this elevator, but for a different car
3485
3487}
3488
3490{
3491 //returns value if fire phase 2 mode is active for this car
3492
3494 return parent->FireServicePhase2;
3495 return 0;
3496}
3497
3499{
3500 //returns true if fire phase 2 mode is active on this elevator, but for a different car
3501
3503}
3504
3505void ElevatorCar::SetControls(const std::string &action_name)
3506{
3507 for (size_t i = 0; i < PanelArray.size(); i++)
3508 {
3509 PanelArray[i]->SetControls(action_name);
3510 }
3511}
3512
3514{
3515 //flash all floor indicators if supported
3516
3517 //only run if power is enabled
3518 if (sbs->GetPower() == false)
3519 return;
3520
3521 for (size_t i = 0; i < FloorIndicatorArray.size(); i++)
3522 FloorIndicatorArray[i]->Flash(value);
3523}
3524
3525CameraTexture* ElevatorCar::AddCameraTexture(const std::string &name, int quality, Real fov, const Vector3 &position, bool use_rotation, const Vector3 &rotation)
3526{
3527 //add a camera texture
3528 CameraTexture* cameratexture = new CameraTexture(this, name, quality, fov, position, use_rotation, rotation);
3529 CameraTextureArray.emplace_back(cameratexture);
3530 return cameratexture;
3531}
3532
3534{
3535 //remove a cameratexture reference (does not delete the object itself)
3536 for (size_t i = 0; i < CameraTextureArray.size(); i++)
3537 {
3538 if (CameraTextureArray[i] == camtex)
3539 {
3540 CameraTextureArray.erase(CameraTextureArray.begin() + i);
3541 return;
3542 }
3543 }
3544}
3545
3546bool ElevatorCar::RespondingToCall(int floor, int direction)
3547{
3548 //returns true if the car is responding to a call on the specified floor
3549
3550 Elevator *e = GetElevator();
3551
3552 //if proceeding to call floor for a call
3553 if (GotoFloor == true && e->GotoFloor == floor && e->GetActiveCallFloor() == e->GotoFloor)
3554 {
3555 //and if a hall call, with the same call direction
3556 if (e->GetActiveCallType() == 1 && e->GetActiveCallDirection() == direction)
3557 return true;
3558 }
3559
3560 return false;
3561}
3562
3564{
3565 //same as other function, but returns the direction of the call
3566
3567 Elevator *e = GetElevator();
3568
3569 //if proceeding to call floor for a call
3570 if (GotoFloor == true && e->GotoFloor == floor && e->GetActiveCallFloor() == e->GotoFloor)
3571 {
3572 //and if a hall call, with the same call direction
3573 if (e->GetActiveCallType() == 1)
3574 return e->GetActiveCallDirection();
3575 }
3576
3577 return 0;
3578}
3579
3580Indicator* 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)
3581{
3582 if (indicator)
3583 return 0;
3584
3585 indicator = new Indicator(this, sound, texture_prefix, blank_texture, direction, CenterX, CenterZ, width, height, voffset, timer_duration);
3586
3587 return indicator;
3588}
3589
3590void ElevatorCar::UpdateKeypadIndicator(const std::string& text, bool play_sound)
3591{
3592 if (indicator)
3593 indicator->Update(text, play_sound);
3594}
3595
3597{
3598 //report which elevator is assigned, on indicator
3599 std::string message = "Requested";
3600
3601 Elevator* e = GetElevator();
3602
3603 //show an error if a floor hasn't been selected due to different factors
3604 if (e->InspectionService == true)
3605 KeypadError();
3606 else if (e->FireServicePhase1 == 1 && e->FireServicePhase2 == 0)
3607 KeypadError();
3608 else if (e->Running == false)
3609 KeypadError();
3610 else if (e->IndependentService == true && (AreDoorsOpen() == false || AreDoorsMoving() != 0))
3611 KeypadError();
3612 else if (e->FireServicePhase2 == 2)
3613 KeypadError();
3614 else if (e->LimitQueue == true && ((e->QueuePositionDirection == 1 && floor < GetFloor() && e->UpQueue.empty() == false) || (e->QueuePositionDirection == -1 && floor > GetFloor() && e->DownQueue.empty() == false)))
3615 KeypadError();
3616 else if (e->LimitQueue == true && e->IsMoving == true && floor == GetFloor())
3617 KeypadError();
3618 else if (GetFloorIndex(floor) == -1)
3619 KeypadError();
3620 else
3621 UpdateKeypadIndicator(message);
3622}
3623
3624bool ElevatorCar::Input(const std::string& text)
3625{
3626 //input a keypad character
3627
3628 //only run if power is enabled
3629 if (sbs->GetPower() == false)
3630 return false;
3631
3632 //only allow single characters
3633 if (text.length() != 1)
3634 return false;
3635
3636 //check lock state
3637 //if (IsLocked() == true)
3638 //return ReportError("Call station is locked");
3639
3640 //erase last character if specified
3641 if (text == "<" && InputCache.size() >= 1)
3642 InputCache.pop_back();
3643
3644 //add text to cache
3645 InputCache += text;
3646
3647 //automatically error if multiple special characters were entered and/or combined with numbers
3648 int StarCount = std::count(InputCache.begin(), InputCache.end(), '*');
3649 int MinCount = std::count(InputCache.begin(), InputCache.end(), '-');
3650 if ((StarCount > 1 || MinCount > 1) && InputCache.length() > 1)
3651 {
3652 keypad_timer->Stop();
3653 InputCache = "";
3654 KeypadError(1);
3655 return true;
3656
3657 //update indicator display
3659
3660 //start timeout timer
3661 keypad_timer->Start(2000, true);
3662
3663 return true;
3664 }
3665
3666
3667 //update indicator display
3669
3670 //verify that the floor entry is valid, error if not
3671 int result = 0;
3672 if (GetFloorFromID(InputCache, result) == false && InputCache != "*" && InputCache != "-")
3673 {
3674 keypad_timer->Stop();
3675 InputCache = "";
3676 KeypadError(1);
3677 return true;
3678 }
3679
3680 //start timeout timer
3681 keypad_timer->Start(TimerDelay * 1000.0f, true);
3682
3683 return true;
3684}
3685
3687{
3688 //process and clear input cache
3689
3690 Elevator* e = GetElevator();
3691
3692 //select recall floor if "0"
3693 if (InputCache == "0" || InputCache == "*")
3694 {
3695 e->SelectFloor(e->GetRecallFloor());
3696 InputCache = "";
3698 return;
3699 }
3700
3701 if (!IsNumeric(InputCache))
3702 {
3703 InputCache = "";
3704 KeypadError();
3705 return;
3706 }
3707
3708 //don't allow input values in the InvalidInput list
3709 for (size_t i = 0; i < InvalidInput.size(); i++)
3710 {
3711 if (InputCache == InvalidInput[i])
3712 {
3713 InputCache = "";
3714 KeypadError();
3715 return;
3716 }
3717 }
3718
3719 int floor = 0;
3720 GetFloorFromID(InputCache, floor);
3721 Requested(floor);
3722 e->SelectFloor(floor);
3723
3724 InputCache = "";
3725}
3726
3727bool ElevatorCar::GetFloorFromID(const std::string& floor, int& result)
3728{
3729 if (!IsNumeric(floor))
3730 return false;
3731
3732 int rawfloor = ToInt(floor);
3733
3734 //convert back to string, to strip off any leading 0's
3735 std::string converted = ToString(rawfloor);
3736
3737 Floor* floorobj = sbs->GetFloorManager()->GetByNumberID(converted);
3738 Floor* floorobj2 = sbs->GetFloorManager()->GetByID(converted);
3739 Floor* floorobj3 = sbs->GetFloorManager()->Get(rawfloor);
3740
3741 if (floorobj)
3742 {
3743 result = floorobj->Number; //get by number ID first
3744 return true;
3745 }
3746 else if (floorobj2)
3747 {
3748 result = floorobj2->Number; //next try floor ID
3749 return true;
3750 }
3751 else if (floorobj3)
3752 {
3753 result = rawfloor; //and last, get by raw floor number
3754 return true;
3755 }
3756
3757 return false;
3758}
3759
3761{
3762 //input timeout timer
3763
3765}
3766
3768{
3769 //if type is 0, standard error
3770 //if type is 1, invalid floor
3771
3772 std::string message = "XX";
3773 if (type == 1)
3774 message = "??";
3775
3776 UpdateKeypadIndicator(message);
3777}
3778
3779bool 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)
3780{
3781 //adds elevator ID signs at the specified position and direction for each serviced floor,
3782 //depending on if the given door number services the floor or not (unless door_number is 0)
3783
3784 Elevator* e = GetElevator();
3785
3786 Real x, z;
3787 if (relative == true)
3788 {
3789 x = GetPosition().x + CenterX;
3790 z = GetPosition().z + CenterZ;
3791 }
3792 else
3793 {
3794 x = CenterX;
3795 z = CenterZ;
3796 }
3797
3798 //make sure specified door exists before continuing
3799 if (door_number != 0)
3800 {
3801 if (DoorExists(door_number) == false)
3802 return ReportError("AddElevatorIDSigns: door " + ToString(door_number) + " does not exist");
3803 }
3804
3805 bool autosize_x, autosize_y;
3806 sbs->GetTextureManager()->GetAutoSize(autosize_x, autosize_y);
3807 sbs->GetTextureManager()->SetAutoSize(false, false);
3808
3809 for (size_t i = 0; i < ServicedFloors.size(); i++)
3810 {
3811 bool door_result = false;
3812 int floor = ServicedFloors[i];
3813 Real base = GetDestinationOffset(floor);
3814
3815 if (door_number != 0)
3816 door_result = ShaftDoorsExist(door_number, floor);
3817
3818 if ((door_number == 0 || door_result == true) && sbs->GetFloor(floor))
3819 {
3820 std::string texture = texture_prefix + e->ID;
3821 std::string tmpdirection = direction;
3822 SetCase(tmpdirection, false);
3823
3824 if (tmpdirection == "front" || tmpdirection == "left")
3825 sbs->DrawWalls(true, false, false, false, false, false);
3826 else
3827 sbs->DrawWalls(false, true, false, false, false, false);
3828
3829 if (tmpdirection == "front" || tmpdirection == "back")
3830 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);
3831 else
3832 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);
3833 sbs->ResetWalls();
3834 }
3835 }
3836 sbs->GetTextureManager()->SetAutoSize(autosize_x, autosize_y);
3837 return true;
3838}
3839
3840Reverb* ElevatorCar::AddReverb(const std::string &name, const std::string &type, const Vector3 &position, Real min_distance, Real max_distance)
3841{
3842 if (reverb)
3843 return 0;
3844
3845 //create a reverb object
3846 reverb = new Reverb(this, name, type, position, min_distance, max_distance, false);
3847 return reverb;
3848}
3849
3851{
3852 return reverb;
3853}
3854
3856{
3857 //remove the reverb
3858 //this does not delete the object
3859
3860 reverb = 0;
3861}
3862
3863
3864}
bool MouseDown()
Definition camera.cpp:1496
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)
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)
ButtonPanel * 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)
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 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:1167
int Number
Definition floor.h:36
Real GetBase(bool relative=false)
Definition floor.cpp:1146
std::string ID
Definition floor.h:38
void SetDirectionalIndicators(int elevator, int car, bool UpLight, bool DownLight)
Definition floor.cpp:1202
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:348
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:1016
void Enabled(bool value)
Definition mesh.cpp:154
Real HitBeam(const Vector3 &origin, const Vector3 &direction, Real max_distance)
Definition mesh.cpp:758
Real GetHeight()
Definition mesh.cpp:726
bool ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
Definition mesh.cpp:689
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
void LoopChildren()
Definition object.cpp:571
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:307
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
virtual void Move(const Vector3 &vector, Real speed=1.0, bool force=false)
Definition object.cpp:259
virtual void Enabled(bool value)
Definition object.h:108
virtual void SetPosition(const Vector3 &position, bool relative=false, bool force=false)
Definition object.cpp:280
virtual void SetPositionY(Real value, bool force=false)
Definition object.cpp:299
bool GetPower()
Definition sbs.cpp:4731
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, bool report=true)
Definition sbs.cpp:690
FloorManager * GetFloorManager()
Definition sbs.cpp:4563
bool IsRunning
Definition sbs.h:157
std::string GetConfigString(const std::string &key, const std::string &default_value)
Definition sbs.cpp:3268
int CarNumber
Definition sbs.h:166
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, bool report=true)
Definition sbs.cpp:927
void ResetWalls(bool ToDefaults=false)
Definition sbs.cpp:1884
bool IsValidFloor(int floor)
Definition sbs.cpp:2522
Floor * GetFloor(int number)
Definition sbs.cpp:1769
bool FastDelete
Definition sbs.h:188
TextureManager * GetTextureManager()
Definition sbs.cpp:4588
Camera * camera
Definition sbs.h:160
int GetFloorNumber(Real altitude, int lastfloor=0, bool checklastfloor=false)
Definition sbs.cpp:1596
int ElevatorNumber
Definition sbs.h:165
bool GetConfigBool(const std::string &key, bool default_value)
Definition sbs.cpp:3273
bool InElevator
Definition sbs.h:163
void DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
Definition sbs.cpp:1863
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:434
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