OSDN Git Service

Added AddEscalator function to floor object
[skyscrapersim/skyscraper.git] / src / sbs / floor.cpp
1 /* $Id$ */
2
3 /*
4         Scalable Building Simulator - Floor Object
5         The Skyscraper Project - Version 1.10 Alpha
6         Copyright (C)2004-2015 Ryan Thoryk
7         http://www.skyscrapersim.com
8         http://sourceforge.net/projects/skyscraper
9         Contact - ryan@tliquest.net
10
11         This program is free software; you can redistribute it and/or
12         modify it under the terms of the GNU General Public License
13         as published by the Free Software Foundation; either version 2
14         of the License, or (at your option) any later version.
15
16         This program is distributed in the hope that it will be useful,
17         but WITHOUT ANY WARRANTY; without even the implied warranty of
18         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19         GNU General Public License for more details.
20
21         You should have received a copy of the GNU General Public License
22         along with this program; if not, write to the Free Software
23         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24 */
25
26 #include "globals.h"
27 #include "sbs.h"
28 #include "floor.h"
29 #include "camera.h"
30 #include "unix.h"
31
32 extern SBS *sbs; //external pointer to the SBS engine
33
34 Floor::Floor(int number)
35 {
36         //set up SBS object
37         SetValues(this, sbs, "Floor", "", false);
38
39         //Set floor's object number
40         Number = number;
41         std::string num = ToString2(Number);
42         SetName(std::string("Floor " + num).c_str());
43
44         //Create primary level mesh
45         Level = new MeshObject(this, std::string("Level " + num).c_str());
46
47         //Create interfloor mesh
48         Interfloor = new MeshObject(this,std::string("Interfloor " + num).c_str());
49
50         //Create columnframe mesh
51         ColumnFrame = new MeshObject(this, std::string("ColumnFrame " + num).c_str());
52
53         //set enabled flags
54         IsEnabled = true;
55         IsColumnFrameEnabled = true;
56         IsInterfloorEnabled = true;
57
58         //init other variables
59         Name = "";
60         ID = "";
61         FloorType = "";
62         Description = "";
63         IndicatorTexture = "";
64         Altitude = 0;
65         Height = 0;
66         InterfloorHeight = 0;
67         EnabledGroup = false;
68         EnabledGroup_Floor = 0;
69 }
70
71 Floor::~Floor()
72 {
73         //Destructor
74
75         //delete escalators
76         for (int i = 0; i < (int)EscalatorArray.size(); i++)
77         {
78                 if (EscalatorArray[i])
79                 {
80                         EscalatorArray[i]->parent_deleting = true;
81                         delete EscalatorArray[i];
82                 }
83                 EscalatorArray[i] = 0;
84         }
85
86         //delete camera textures
87         for (int i = 0; i < (int)CameraTextureArray.size(); i++)
88         {
89                 if (CameraTextureArray[i])
90                 {
91                         CameraTextureArray[i]->parent_deleting = true;
92                         delete CameraTextureArray[i];
93                 }
94                 CameraTextureArray[i] = 0;
95         }
96
97         //delete controls
98         for (int i = 0; i < (int)ControlArray.size(); i++)
99         {
100                 if (ControlArray[i])
101                 {
102                         ControlArray[i]->parent_deleting = true;
103                         delete ControlArray[i];
104                 }
105                 ControlArray[i] = 0;
106         }
107
108         //delete triggers
109         for (int i = 0; i < (int)TriggerArray.size(); i++)
110         {
111                 if (TriggerArray[i])
112                 {
113                         TriggerArray[i]->parent_deleting = true;
114                         delete TriggerArray[i];
115                 }
116                 TriggerArray[i] = 0;
117         }
118
119         //delete models
120         for (int i = 0; i < (int)ModelArray.size(); i++)
121         {
122                 if (ModelArray[i])
123                 {
124                         ModelArray[i]->parent_deleting = true;
125                         delete ModelArray[i];
126                 }
127                 ModelArray[i] = 0;
128         }
129
130         //delete lights
131         for (int i = 0; i < (int)lights.size(); i++)
132         {
133                 if (lights[i])
134                 {
135                         lights[i]->parent_deleting = true;
136                         delete lights[i];
137                 }
138                 lights[i] = 0;
139         }
140
141         //delete call buttons
142         for (int i = 0; i < (int)CallButtonArray.size(); i++)
143         {
144                 if (CallButtonArray[i])
145                 {
146                         CallButtonArray[i]->parent_deleting = true;
147                         delete CallButtonArray[i];
148                 }
149                 CallButtonArray[i] = 0;
150         }
151
152         //delete doors
153         for (int i = 0; i < (int)DoorArray.size(); i++)
154         {
155                 if (DoorArray[i])
156                 {
157                         DoorArray[i]->parent_deleting = true;
158                         delete DoorArray[i];
159                 }
160                 DoorArray[i] = 0;
161         }
162
163         //delete floor indicators
164         for (int i = 0; i < (int)FloorIndicatorArray.size(); i++)
165         {
166                 if (FloorIndicatorArray[i])
167                 {
168                         FloorIndicatorArray[i]->parent_deleting = true;
169                         delete FloorIndicatorArray[i];
170                 }
171                 FloorIndicatorArray[i] = 0;
172         }
173
174         //delete directional indicators
175         for (int i = 0; i < (int)DirIndicatorArray.size(); i++)
176         {
177                 if (DirIndicatorArray[i])
178                 {
179                         DirIndicatorArray[i]->parent_deleting = true;
180                         delete DirIndicatorArray[i];
181                 }
182                 DirIndicatorArray[i] = 0;
183         }
184
185         //delete sounds
186         for (int i = 0; i < (int)sounds.size(); i++)
187         {
188                 if (sounds[i])
189                 {
190                         sounds[i]->parent_deleting = true;
191                         delete sounds[i];
192                 }
193                 sounds[i] = 0;
194         }
195
196         //delete meshes
197         if (Level)
198         {
199                 Level->parent_deleting = true;
200                 delete Level;
201         }
202         Level = 0;
203
204         if (Interfloor)
205         {
206                 Interfloor->parent_deleting = true;
207                 delete Interfloor;
208         }
209         Interfloor = 0;
210
211         if (ColumnFrame)
212         {
213                 ColumnFrame->parent_deleting = true;
214                 delete ColumnFrame;
215         }
216         ColumnFrame = 0;
217
218         //delete walls in external mesh
219         if (sbs->FastDelete == false)
220                 sbs->External->DeleteWalls(this);
221
222         //unregister from parent
223         if (sbs->FastDelete == false && parent_deleting == false)
224                 sbs->RemoveFloor(this);
225 }
226
227 WallObject* Floor::AddFloor(const char *name, const char *texture, float thickness, float x1, float z1, float x2, float z2, float voffset1, float voffset2, bool reverse_axis, bool texture_direction, float tw, float th, bool isexternal, bool legacy_behavior)
228 {
229         //Adds a floor with the specified dimensions and vertical offset
230
231         WallObject *wall;
232
233         if (isexternal == false)
234         {
235                 wall = Level->CreateWallObject(name);
236                 sbs->AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, GetBase(true) + voffset1, GetBase(true) + voffset2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
237         }
238         else
239         {
240                 wall = sbs->External->CreateWallObject(name);
241                 sbs->AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, Altitude + voffset1, Altitude + voffset2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
242         }
243         return wall;
244 }
245
246 WallObject* Floor::AddInterfloorFloor(const char *name, const char *texture, float thickness, float x1, float z1, float x2, float z2, float voffset1, float voffset2, bool reverse_axis, bool texture_direction, float tw, float th, bool legacy_behavior)
247 {
248         //Adds an interfloor floor with the specified dimensions and vertical offset
249
250         WallObject *wall = Interfloor->CreateWallObject(name);
251         sbs->AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, voffset1, voffset2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
252         return wall;
253 }
254
255 WallObject* Floor::AddWall(const char *name, const char *texture, float thickness, float x1, float z1, float x2, float z2, float height_in1, float height_in2, float voffset1, float voffset2, float tw, float th, bool isexternal)
256 {
257         //Adds a wall with the specified dimensions
258
259         WallObject *wall;
260         if (isexternal == false)
261         {
262                 wall = Level->CreateWallObject(name);
263                 sbs->AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height_in1, height_in2, GetBase(true) + voffset1, GetBase(true) + voffset2, tw, th, true);
264         }
265         else
266         {
267                 wall = sbs->External->CreateWallObject(name);
268                 sbs->AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height_in1, height_in2, Altitude + voffset1, Altitude + voffset2, tw, th, true);
269         }
270         return wall;
271 }
272
273 WallObject* Floor::AddInterfloorWall(const char *name, const char *texture, float thickness, float x1, float z1, float x2, float z2, float height_in1, float height_in2, float voffset1, float voffset2, float tw, float th)
274 {
275         //Adds an interfloor wall with the specified dimensions
276
277         WallObject *wall = Interfloor->CreateWallObject(name);
278         sbs->AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height_in1, height_in2, voffset1, voffset2, tw, th, true);
279         return wall;
280 }
281
282 void Floor::Enabled(bool value)
283 {
284         //turns floor on/off
285
286         if (IsEnabled == value)
287                 return;
288
289         SBS_PROFILE("Floor::Enabled");
290         Level->Enable(value);
291         IsEnabled = value;
292
293         if (sbs->Verbose)
294         {
295                 if (value == true)
296                         Report("Enabled");
297                 else
298                         Report("Disabled");
299         }
300
301         //handle interfloors
302         if (value == false)
303         {
304                 if (sbs->InterfloorOnTop == false)
305                 {
306                         //only turn off interfloor if floor below is disabled
307                         Floor *floor = sbs->GetFloor(Number - 1);
308                         if (floor)
309                         {
310                                 if (floor->IsEnabled == false)
311                                         EnableInterfloor(false);
312                         }
313                         else
314                                 EnableInterfloor(false);
315
316                         //turn off adjacent interfloor
317                         floor = sbs->GetFloor(Number + 1);
318                         if (floor)
319                         {
320                                 if (floor->IsEnabled == false)
321                                         floor->EnableInterfloor(false);
322                         }
323                 }
324                 else
325                 {
326                         //only turn off interfloor if floor above is disabled
327                         Floor *floor = sbs->GetFloor(Number + 1);
328                         if (floor)
329                         {
330                                 if (floor->IsEnabled == false)
331                                         EnableInterfloor(false);
332                         }
333                         else
334                                 EnableInterfloor(false);
335
336                         //turn off adjacent interfloor
337                         floor = sbs->GetFloor(Number - 1);
338                         if (floor)
339                         {
340                                 if (floor->IsEnabled == false)
341                                         floor->EnableInterfloor(false);
342                         }
343                 }
344         }
345         else
346         {
347                 if (sbs->InterfloorOnTop == false)
348                 {
349                         //turn on interfloor for next floor
350                         if (sbs->GetFloor(Number + 1))
351                                 sbs->GetFloor(Number + 1)->EnableInterfloor(true);
352                 }
353                 else
354                 {
355                         //turn on interfloor for previous floor
356                         if (sbs->GetFloor(Number - 1))
357                                 sbs->GetFloor(Number - 1)->EnableInterfloor(true);
358                 }
359                 EnableInterfloor(true);
360         }
361
362         EnableColumnFrame(value);
363
364         //controls
365         for (size_t i = 0; i < (int)ControlArray.size(); i++)
366         {
367                 if (ControlArray[i])
368                         ControlArray[i]->Enabled(value);
369         }
370
371         //triggers
372         for (size_t i = 0; i < (int)TriggerArray.size(); i++)
373         {
374                 if (TriggerArray[i])
375                         TriggerArray[i]->Enabled(value);
376         }
377
378         //models
379         for (size_t i = 0; i < (int)ModelArray.size(); i++)
380         {
381                 if (ModelArray[i])
382                         ModelArray[i]->Enable(value);
383         }
384
385         //call buttons
386         for (size_t i = 0; i < (int)CallButtonArray.size(); i++)
387         {
388                 if (CallButtonArray[i])
389                         CallButtonArray[i]->Enabled(value);
390         }
391
392         //doors
393         for (size_t i = 0; i < (int)DoorArray.size(); i++)
394         {
395                 if (DoorArray[i])
396                         DoorArray[i]->Enabled(value);
397         }
398
399         //turn on/off directional indicators
400         for (int i = 0; i < (int)DirIndicatorArray.size(); i++)
401         {
402                 if (DirIndicatorArray[i])
403                         DirIndicatorArray[i]->Enabled(value);
404         }
405         UpdateDirectionalIndicators();
406
407         //floor indicators
408         for (int i = 0; i < (int)FloorIndicatorArray.size(); i++)
409         {
410                 if (FloorIndicatorArray[i])
411                         FloorIndicatorArray[i]->Enabled(value);
412         }
413         //update floor indicator values
414         UpdateFloorIndicators();
415
416         //sounds
417         for (int i = 0; i < (int)sounds.size(); i++)
418         {
419                 if (sounds[i])
420                 {
421                         if (sounds[i]->GetLoopState() == true)
422                         {
423                                 if (value == false)
424                                         sounds[i]->Stop();
425                                 else
426                                         sounds[i]->Play();
427                         }
428                 }
429         }
430 }
431
432 float Floor::FullHeight()
433 {
434         //calculate full height of a floor
435         return InterfloorHeight + Height;
436 }
437
438 Object* Floor::AddCallButtons(std::vector<int> &elevators, const char *sound_file, const char *BackTexture, const char *UpButtonTexture, const char *UpButtonTexture_Lit, const char *DownButtonTexture, const char *DownButtonTexture_Lit, float CenterX, float CenterZ, float voffset, const char *direction, float BackWidth, float BackHeight, bool ShowBack, float tw, float th)
439 {
440         //adds call buttons
441
442         //check if any of the elevators serve the current floor
443         bool check = false;
444         for (int i = 0; i < (int)elevators.size(); i++)
445         {
446                 Elevator *elev = sbs->GetElevator(elevators[i]);
447                 if (elev)
448                 {
449                         if (elev->IsServicedFloor(Number) == true)
450                         {
451                                 check = true;
452                                 break;
453                         }
454                 }
455         }
456
457         //exit if none of the elevators serve the floor
458         if (check == false)
459                 return 0;
460
461         //create call button
462         int Current = (int)CallButtonArray.size();
463         CallButton *button = new CallButton(elevators, Number, Current, sound_file, BackTexture, UpButtonTexture, UpButtonTexture_Lit, DownButtonTexture, DownButtonTexture_Lit, CenterX, CenterZ, voffset, direction, BackWidth, BackHeight, ShowBack, tw, th);
464         CallButtonArray.push_back(button);
465         return button;
466 }
467
468 void Floor::Cut(const Ogre::Vector3 &start, const Ogre::Vector3 &end, bool cutwalls, bool cutfloors, bool fast, int checkwallnumber, bool prepare)
469 {
470         //caller to SBS cut function
471         //Y values are relative to the floor's altitude
472         //if fast is specified, skips the interfloor scan
473
474         for (int i = 0; i < (int)Level->Walls.size(); i++)
475         {
476                 bool reset = true;
477                 if (i > 0)
478                         reset = false;
479
480                 sbs->Cut(Level->Walls[i], Ogre::Vector3(start.x, start.y, start.z), Ogre::Vector3(end.x, end.y, end.z), cutwalls, cutfloors, checkwallnumber, reset);
481         }
482         if (fast == false)
483         {
484                 for (int i = 0; i < (int)Interfloor->Walls.size(); i++)
485                 {
486                         sbs->Cut(Interfloor->Walls[i], Ogre::Vector3(start.x, start.y, start.z), Ogre::Vector3(end.x, end.y, end.z), cutwalls, cutfloors, checkwallnumber, false);
487                 }
488         }
489 }
490
491 void Floor::CutAll(const Ogre::Vector3 &start, const Ogre::Vector3 &end, bool cutwalls, bool cutfloors, bool prepare)
492 {
493         //cuts all objects related to this floor (floor, interfloor, shafts, stairs and external)
494         //Y values are relative to the floor's altitude
495
496         //cut current level
497         Cut(start, end, cutwalls, cutfloors, false);
498
499         //cut shafts
500         for (int i = 1; i <= sbs->Shafts(); i++)
501         {
502                 if (sbs->GetShaft(i))
503                         sbs->GetShaft(i)->Cut(false, Number, start, end, cutwalls, cutfloors);
504         }
505
506         //cut stairs
507         for (int i = 1; i <= sbs->StairsNum(); i++)
508         {
509                 if (sbs->GetStairs(i))
510                         sbs->GetStairs(i)->Cut(false, Number, start, end, cutwalls, cutfloors);
511         }
512
513         //cut external
514         for (int i = 0; i < (int)sbs->External->Walls.size(); i++)
515                 sbs->Cut(sbs->External->Walls[i], Ogre::Vector3(start.x, Altitude + start.y, start.z), Ogre::Vector3(end.x, Altitude + end.y, end.z), cutwalls, cutfloors);
516 }
517
518 void Floor::AddGroupFloor(int number)
519 {
520         //adds a floor number to the group list.
521         //Groups are used to enable multiple floors at the same time when
522         //a user arrives at a floor
523
524         if (IsInGroup(number))
525                 return;
526
527         Group.push_back(number);
528         std::sort(Group.begin(), Group.end());
529 }
530
531 void Floor::RemoveGroupFloor(int number)
532 {
533         //removes a floor number from the group list
534
535         for (int i = 0; i < (int)Group.size(); i++)
536         {
537                 if (Group[i] == number)
538                 {
539                         Group.erase(Group.begin() + i);
540                         return;
541                 }
542         }
543 }
544
545 void Floor::EnableGroup(bool value)
546 {
547         //enable floors grouped with this floor
548
549         SBS_PROFILE("Floor::EnableGroup");
550         if (Group.size() > 0)
551         {
552                 for (size_t i = 0; i < Group.size(); i++)
553                 {
554                         Floor *floor = sbs->GetFloor(Group[i]);
555
556                         //check if floor exists
557                         if (floor)
558                         {
559                                 //enable other floor
560                                 floor->Enabled(value);
561
562                                 if (value == true)
563                                 {
564                                         floor->EnabledGroup = true;
565                                         floor->EnabledGroup_Floor = Number;
566                                 }
567                                 else
568                                 {
569                                         floor->EnabledGroup = false;
570                                         floor->EnabledGroup_Floor = 0;
571                                 }
572
573                                 //enable shafts and stairs for other floor
574                                 for (int j = 1; j <= sbs->Shafts(); j++)
575                                 {
576                                         Shaft *shaft = sbs->GetShaft(j);
577                                         if (shaft)
578                                         {
579                                                 if (shaft->IsEnabled == false)
580                                                         shaft->Enabled(Group[i], value, true);
581                                         }
582                                 }
583                                 for (int j = 1; j <= sbs->StairsNum(); j++)
584                                 {
585                                         Stairs *stairs = sbs->GetStairs(j);
586                                         if (stairs)
587                                         {
588                                                 if (stairs->IsEnabled == false)
589                                                         stairs->Enabled(Group[i], value);
590                                         }
591                                 }
592                         }
593                 }
594         }
595 }
596
597 bool Floor::IsInGroup(int floor)
598 {
599         //return true if the specified floor is in the group listing
600
601         if (Group.size() > 0)
602         {
603                 for (size_t i = 0; i < Group.size(); i++)
604                 {
605                         if (Group[i] == floor)
606                                 return true;
607                 }
608         }
609         return false;
610 }
611
612 Object* Floor::AddDoor(const char *open_sound, const char *close_sound, bool open_state, const char *texture, float thickness, int direction, float speed, float CenterX, float CenterZ, float width, float height, float voffset, float tw, float th)
613 {
614         //interface to the SBS AddDoor function
615
616         if (direction > 8 || direction < 1)
617         {
618                 ReportError("Door direction out of range");
619                 return 0;
620         }
621
622         float x1, z1, x2, z2;
623         //set up coordinates
624         if (direction < 5)
625         {
626                 x1 = CenterX;
627                 x2 = CenterX;
628                 z1 = CenterZ - (width / 2);
629                 z2 = CenterZ + (width / 2);
630         }
631         else
632         {
633                 x1 = CenterX - (width / 2);
634                 x2 = CenterX + (width / 2);
635                 z1 = CenterZ;
636                 z2 = CenterZ;
637         }
638
639         //cut area
640         if (direction < 5)
641                 CutAll(Ogre::Vector3(x1 - 1, GetBase(true) + voffset, z1), Ogre::Vector3(x2 + 1, GetBase(true) + voffset + height, z2), true, false);
642         else
643                 CutAll(Ogre::Vector3(x1, GetBase(true) + voffset, z1 - 1), Ogre::Vector3(x2, GetBase(true) + voffset + height, z2 + 1), true, false);
644
645         int number = (int)DoorArray.size();
646         std::string name = "Floor " + ToString2(Number) + ":Door " + ToString2(number);
647         Door* door = new Door(this, name.c_str(), open_sound, close_sound, open_state, texture, thickness, direction, speed, CenterX, CenterZ, width, height, GetBase(true) + voffset, tw, th);
648         DoorArray.push_back(door);
649         return door;
650 }
651
652 bool Floor::CalculateAltitude()
653 {
654         //calculate the floor's altitude in relation to floor below (or above it, if it's a basement level)
655         //and return the altitude value
656         //if the related floor does not have an adjacent floor, return false
657
658         if (Altitude == 0)
659         {
660                 if (Number > 0)
661                 {
662                         if (sbs->GetFloor(Number - 1))
663                                 Altitude = sbs->GetFloor(Number - 1)->Altitude + sbs->GetFloor(Number - 1)->FullHeight();
664                         else
665                         {
666                                 return ReportError("Invalid floor number specified - no adjacent floor");
667                         }
668                 }
669
670                 if (Number == -1)
671                         Altitude = -FullHeight();
672
673                 if (Number < -1)
674                 {
675                         if (sbs->GetFloor(Number + 1))
676                                 Altitude = sbs->GetFloor(Number + 1)->Altitude - FullHeight();
677                         else
678                                 return ReportError("Invalid floor number specified - no adjacent floor");
679                 }
680         }
681
682         //set altitude
683         SetAltitude(Altitude);
684
685         return true;
686 }
687
688 void Floor::EnableColumnFrame(bool value)
689 {
690         //enable/disable columnframe mesh
691         ColumnFrame->Enable(value);
692         IsColumnFrameEnabled = value;
693 }
694
695 void Floor::EnableInterfloor(bool value)
696 {
697         //enable/disable interfloor mesh
698         Interfloor->Enable(value);
699         IsInterfloorEnabled = value;
700 }
701
702 WallObject* Floor::ColumnWallBox(const char *name, const char *texture, float x1, float x2, float z1, float z2, float height_in, float voffset, float tw, float th, bool inside, bool outside, bool top, bool bottom)
703 {
704         //create columnframe wall box
705
706         WallObject *wall = ColumnFrame->CreateWallObject(name);
707         sbs->CreateWallBox(wall, name, texture, x1, x2, z1, z2, height_in, voffset, tw, th, inside, outside, top, bottom, true);
708         return wall;
709 }
710
711 WallObject* Floor::ColumnWallBox2(const char *name, const char *texture, float CenterX, float CenterZ, float WidthX, float LengthZ, float height_in, float voffset, float tw, float th, bool inside, bool outside, bool top, bool bottom)
712 {
713         //create columnframe wall box from a central location
714
715         WallObject *wall = ColumnFrame->CreateWallObject(name);
716         sbs->CreateWallBox2(wall, name, texture, CenterX, CenterZ, WidthX, LengthZ, height_in, voffset, tw, th, inside, outside, top, bottom, true);
717         return wall;
718 }
719
720 Object* Floor::AddFloorIndicator(int elevator, bool relative, const char *texture_prefix, const char *direction, float CenterX, float CenterZ, float width, float height, float voffset)
721 {
722         //Creates a floor indicator at the specified location
723
724         if (relative == false)
725         {
726                 FloorIndicator *ind = new FloorIndicator(this, elevator, texture_prefix, direction, CenterX, CenterZ, width, height, GetBase(true) + voffset);
727                 FloorIndicatorArray.push_back(ind);
728                 return ind;
729         }
730         else
731         {
732                 Elevator* elev = sbs->GetElevator(elevator);
733                 if (elev)
734                 {
735                         FloorIndicator *ind = new FloorIndicator(this, elevator, texture_prefix, direction, elev->GetPosition().x + CenterX, elev->GetPosition().z + CenterZ, width, height, GetBase(true) + voffset);
736                         FloorIndicatorArray.push_back(ind);
737                         return ind;
738                 }
739                 else
740                         return 0;
741         }
742 }
743
744 void Floor::UpdateFloorIndicators(int elevator)
745 {
746         //updates a floor indicator for a specified elevator
747
748         for (int i = 0; i < (int)FloorIndicatorArray.size(); i++)
749         {
750                 if (FloorIndicatorArray[i])
751                 {
752                         if (FloorIndicatorArray[i]->elev == elevator)
753                                 FloorIndicatorArray[i]->Update();
754                 }
755         }
756 }
757
758 void Floor::UpdateFloorIndicators()
759 {
760         //updates all floor indicators
761
762         for (int i = 0; i < (int)FloorIndicatorArray.size(); i++)
763         {
764                 if (FloorIndicatorArray[i])
765                         FloorIndicatorArray[i]->Update();
766         }
767 }
768
769 void Floor::Loop()
770 {
771         //floor object main loop; runs if camera is currently on this floor
772
773         if (IsEnabled == true)
774         {
775                 for (int i = 0; i < (int)TriggerArray.size(); i++)
776                 {
777                         if (TriggerArray[i])
778                                 TriggerArray[i]->Check();
779                 }
780         }
781 }
782
783 std::vector<int> Floor::GetCallButtons(int elevator)
784 {
785         //get numbers of call buttons that service the specified elevator
786
787         std::vector<int> buttons;
788         buttons.reserve(CallButtonArray.size());
789         for (int i = 0; i < (int)CallButtonArray.size(); i++)
790         {
791                 //put button number onto the array if it serves the elevator
792                 if (CallButtonArray[i])
793                 {
794                         if (CallButtonArray[i]->ServicesElevator(elevator) == true)
795                                 buttons.push_back(i);
796                 }
797         }
798         return buttons;
799 }
800
801 CallButton* Floor::GetCallButton(int elevator)
802 {
803         //returns the first call button object that services the specified elevator
804
805         for (int i = 0; i < (int)CallButtonArray.size(); i++)
806         {
807                 if (CallButtonArray[i])
808                 {
809                         if (CallButtonArray[i]->ServicesElevator(elevator) == true)
810                                 return CallButtonArray[i];
811                 }
812         }
813         return 0;
814 }
815
816 void Floor::AddFillerWalls(const char *texture, float thickness, float CenterX, float CenterZ, float width, float height, float voffset, bool direction, float tw, float th)
817 {
818         //convenience function for adding filler walls around doors
819         //direction is either "false" for a door that faces left/right, or "true" for one that faces front/back
820
821         float x1 = 0, x2 = 0, z1 = 0, z2 = 0, depth1 = 0, depth2 = 0;
822
823         //exit if no height given
824         if (height == 0.0f)
825         {
826                 ReportError("AddFillerWalls: no wall height specified");
827                 return;
828         }
829
830         if (sbs->GetWallOrientation() == 0)
831         {
832                 depth1 = 0;
833                 depth2 = thickness;
834         }
835         if (sbs->GetWallOrientation() == 1)
836         {
837                 depth1 = thickness / 2;
838                 depth2 = thickness / 2;
839         }
840         if (sbs->GetWallOrientation() == 2)
841         {
842                 depth1 = thickness;
843                 depth2 = 0;
844         }
845
846         if (direction == false)
847         {
848                 //door faces left/right
849                 x1 = CenterX - depth1;
850                 x2 = CenterX + depth2;
851                 z1 = CenterZ - (width / 2);
852                 z2 = CenterZ + (width / 2);
853         }
854         else
855         {
856                 //door faces front/back
857                 x1 = CenterX - (width / 2);
858                 x2 = CenterX + (width / 2);
859                 z1 = CenterZ - depth1;
860                 z2 = CenterZ + depth2;
861         }
862
863         //perform a cut in the area
864         CutAll(Ogre::Vector3(x1, GetBase(true) + voffset, z1), Ogre::Vector3(x2, GetBase(true) + voffset + height, z2), true, false);
865
866         //create walls
867         sbs->DrawWalls(false, true, false, false, false, false);
868         if (direction == false)
869                 AddWall("FillerWallLeft", texture, 0, x1, z1, x2, z1, height, height, voffset, voffset, tw, th, false);
870         else
871                 AddWall("FillerWallLeft", texture, 0, x1, z1, x1, z2, height, height, voffset, voffset, tw, th, false);
872         sbs->ResetWalls();
873
874         sbs->DrawWalls(true, false, false, false, false, false);
875         if (direction == false)
876                 AddWall("FillerWallRight", texture, 0, x1, z2, x2, z2, height, height, voffset, voffset, tw, th, false);
877         else
878                 AddWall("FillerWallRight", texture, 0, x2, z1, x2, z2, height, height, voffset, voffset, tw, th, false);
879
880         AddFloor("FillerWallTop", texture, 0, x1, z1, x2, z2, height + voffset, height + voffset, false, false, tw, th, false);
881         sbs->ResetWalls();
882 }
883
884 Object* Floor::AddSound(const char *name, const char *filename, Ogre::Vector3 position, bool loop, float volume, int speed, float min_distance, float max_distance, float doppler_level, float cone_inside_angle, float cone_outside_angle, float cone_outside_volume, Ogre::Vector3 direction)
885 {
886         //create a looping sound object
887
888         Sound *sound = new Sound(this, name, false);
889         sounds.push_back(sound);
890
891         //set parameters and play sound
892         sound->Move(position.x, GetBase(true) + position.y, position.z);
893         sound->SetDirection(direction);
894         sound->SetVolume(volume);
895         sound->SetSpeed(speed);
896         sound->SetDistances(min_distance, max_distance);
897         sound->SetDirection(direction);
898         sound->SetDopplerLevel(doppler_level);
899         sound->SetConeSettings(cone_inside_angle, cone_outside_angle, cone_outside_volume);
900         sound->Load(filename);
901         sound->Loop(loop);
902         if (loop && sbs->IsRunning == true && sbs->camera->CurrentFloor == Number)
903                 sound->Play();
904
905         return sound;
906 }
907
908 std::vector<Sound*> Floor::GetSound(const char *name)
909 {
910         //get sound by name
911
912         std::string findname = name;
913         SetCase(findname, false);
914         std::vector<Sound*> soundlist;
915         for (int i = 0; i < (int)sounds.size(); i++)
916         {
917                 if (sounds[i])
918                 {
919                         std::string name2 = sounds[i]->GetName();
920                         SetCase(name2, false);
921                         if (findname == name2)
922                                 soundlist.push_back(sounds[i]);
923                 }
924         }
925         return soundlist;
926 }
927
928 void Floor::Report(std::string message)
929 {
930         //general reporting function
931         sbs->Report("Floor " + ToString2(Number) + ": " + message);
932 }
933
934 bool Floor::ReportError(std::string message)
935 {
936         //general reporting function
937         return sbs->ReportError("Floor " + ToString2(Number) + ": " + message);
938 }
939
940 float Floor::GetBase(bool relative)
941 {
942         //returns the base of the floor
943         //if Interfloor is on the bottom of the level (by default), the base is GetBase()
944         //otherwise the base is just altitude
945         if (relative == false)
946         {
947                 if (sbs->InterfloorOnTop == false)
948                         return Altitude + InterfloorHeight;
949                 else
950                         return Altitude;
951         }
952         else
953         {
954                 if (sbs->InterfloorOnTop == false)
955                         return InterfloorHeight;
956                 else
957                         return 0;
958         }
959 }
960
961 Object* Floor::AddDirectionalIndicator(int elevator, bool relative, bool active_direction, bool single, bool vertical, const char *BackTexture, const char *uptexture, const char *uptexture_lit, const char *downtexture, const char *downtexture_lit, float CenterX, float CenterZ, float voffset, const char *direction, float BackWidth, float BackHeight, bool ShowBack, float tw, float th)
962 {
963         //create a directional indicator on the specified floor, associated with a given elevator
964
965         if (sbs->Verbose)
966                 Report("adding directional indicator");
967
968         Elevator *elev = sbs->GetElevator(elevator);
969         if (!elev)
970                 return 0;
971
972         float x, z;
973         if (relative == true)
974         {
975                 x = elev->GetPosition().x + CenterX;
976                 z = elev->GetPosition().z + CenterZ;
977         }
978         else
979         {
980                 x = CenterX;
981                 z = CenterZ;
982         }
983
984         if (active_direction == false)
985         {
986                 //if active_direction is false, only create indicator if the elevator serves the floor
987                 if (elev->IsServicedFloor(Number) == false)
988                         return 0;
989         }
990
991         DirectionalIndicator *indicator = new DirectionalIndicator(this, elevator, Number, active_direction, single, vertical, BackTexture, uptexture, uptexture_lit, downtexture, downtexture_lit, x, z, GetBase(true) + voffset, direction, BackWidth, BackHeight, ShowBack, tw, th);
992         DirIndicatorArray.push_back(indicator);
993         return indicator;
994 }
995
996 void Floor::SetDirectionalIndicators(int elevator, bool UpLight, bool DownLight)
997 {
998         //set light status of all standard (non active-direction) directional indicators associated with the given elevator
999
1000         for (int i = 0; i < (int)DirIndicatorArray.size(); i++)
1001         {
1002                 DirectionalIndicator *indicator = DirIndicatorArray[i];
1003
1004                 if (indicator)
1005                 {
1006                         if (indicator->elevator == elevator && indicator->ActiveDirection == false)
1007                         {
1008                                 indicator->DownLight(DownLight);
1009                                 indicator->UpLight(UpLight);
1010                         }
1011                 }
1012         }
1013 }
1014
1015 void Floor::UpdateDirectionalIndicators(int elevator)
1016 {
1017         //updates the active-direction indicators associated with the given elevator
1018
1019         SBS_PROFILE("Floor::UpdateDirectionalIndicators1");
1020         for (int i = 0; i < (int)DirIndicatorArray.size(); i++)
1021         {
1022                 DirectionalIndicator *indicator = DirIndicatorArray[i];
1023
1024                 if (indicator)
1025                 {
1026                         if (indicator->elevator == elevator && indicator->ActiveDirection == true)
1027                         {
1028                                 Elevator *elev = sbs->GetElevator(elevator);
1029
1030                                 if (!elev)
1031                                         return;
1032
1033                                 if (elev->ActiveDirection == 1)
1034                                 {
1035                                         indicator->UpLight(true);
1036                                         indicator->DownLight(false);
1037                                 }
1038                                 if (elev->ActiveDirection == 0)
1039                                 {
1040                                         indicator->UpLight(false);
1041                                         indicator->DownLight(false);
1042                                 }
1043                                 if (elev->ActiveDirection == -1)
1044                                 {
1045                                         indicator->UpLight(false);
1046                                         indicator->DownLight(true);
1047                                 }
1048                         }
1049                 }
1050         }
1051 }
1052
1053 void Floor::UpdateDirectionalIndicators()
1054 {
1055         //updates all active-direction indicators
1056
1057         SBS_PROFILE("Floor::UpdateDirectionalIndicators2");
1058         std::string value;
1059         for (int i = 0; i < (int)DirIndicatorArray.size(); i++)
1060         {
1061                 DirectionalIndicator *indicator = DirIndicatorArray[i];
1062
1063                 if (indicator)
1064                 {
1065                         if (indicator->ActiveDirection == true)
1066                         {
1067                                 Elevator *elev = sbs->GetElevator(indicator->elevator);
1068
1069                                 if (!elev)
1070                                         return;
1071
1072                                 if (elev->ActiveDirection == 1)
1073                                 {
1074                                         indicator->UpLight(true);
1075                                         indicator->DownLight(false);
1076                                 }
1077                                 if (elev->ActiveDirection == 0)
1078                                 {
1079                                         indicator->UpLight(false);
1080                                         indicator->DownLight(false);
1081                                 }
1082                                 if (elev->ActiveDirection == -1)
1083                                 {
1084                                         indicator->UpLight(false);
1085                                         indicator->DownLight(true);
1086                                 }
1087                         }
1088                 }
1089         }
1090 }
1091
1092 Door* Floor::GetDoor(int number)
1093 {
1094         //get door object
1095         if (number < (int)DoorArray.size())
1096         {
1097                 if (DoorArray[number])
1098                         return DoorArray[number];
1099         }
1100
1101         return 0;
1102 }
1103
1104 void Floor::RemoveCallButton(CallButton *callbutton)
1105 {
1106         //remove a call button object from the array
1107         //this does not delete the object
1108         for (int i = 0; i < (int)CallButtonArray.size(); i++)
1109         {
1110                 if (CallButtonArray[i] == callbutton)
1111                 {
1112                         CallButtonArray.erase(CallButtonArray.begin() + i);
1113                         return;
1114                 }
1115         }
1116 }
1117
1118 void Floor::RemoveFloorIndicator(FloorIndicator *indicator)
1119 {
1120         //remove a floor indicator from the array
1121         //this does not delete the object
1122         for (int i = 0; i < (int)FloorIndicatorArray.size(); i++)
1123         {
1124                 if (FloorIndicatorArray[i] == indicator)
1125                 {
1126                         FloorIndicatorArray.erase(FloorIndicatorArray.begin() + i);
1127                         return;
1128                 }
1129         }
1130 }
1131
1132 void Floor::RemoveDirectionalIndicator(DirectionalIndicator *indicator)
1133 {
1134         //remove a directional indicator from the array
1135         //this does not delete the object
1136         for (int i = 0; i < (int)DirIndicatorArray.size(); i++)
1137         {
1138                 if (DirIndicatorArray[i] == indicator)
1139                 {
1140                         DirIndicatorArray.erase(DirIndicatorArray.begin() + i);
1141                         return;
1142                 }
1143         }
1144 }
1145
1146 void Floor::RemoveDoor(Door *door)
1147 {
1148         //remove a door from the array
1149         //this does not delete the object
1150         for (int i = 0; i < (int)DoorArray.size(); i++)
1151         {
1152                 if (DoorArray[i] == door)
1153                 {
1154                         DoorArray.erase(DoorArray.begin() + i);
1155                         return;
1156                 }
1157         }
1158 }
1159
1160 void Floor::RemoveSound(Sound *sound)
1161 {
1162         //remove a sound from the array
1163         //this does not delete the object
1164         for (int i = 0; i < (int)sounds.size(); i++)
1165         {
1166                 if (sounds[i] == sound)
1167                 {
1168                         sounds.erase(sounds.begin() + i);
1169                         return;
1170                 }
1171         }
1172 }
1173
1174 void Floor::RemoveLight(Light *light)
1175 {
1176         //remove a light reference (does not delete the object itself)
1177         for (int i = 0; i < (int)lights.size(); i++)
1178         {
1179                 if (lights[i] == light)
1180                 {
1181                         lights.erase(lights.begin() + i);
1182                         return;
1183                 }
1184         }
1185 }
1186
1187 void Floor::RemoveModel(Model *model)
1188 {
1189         //remove a model reference (does not delete the object itself)
1190         for (int i = 0; i < (int)ModelArray.size(); i++)
1191         {
1192                 if (ModelArray[i] == model)
1193                 {
1194                         ModelArray.erase(ModelArray.begin() + i);
1195                         return;
1196                 }
1197         }
1198 }
1199
1200 void Floor::RemoveControl(Control *control)
1201 {
1202         //remove a control reference (does not delete the object itself)
1203         for (int i = 0; i < (int)ControlArray.size(); i++)
1204         {
1205                 if (ControlArray[i] == control)
1206                 {
1207                         ControlArray.erase(ControlArray.begin() + i);
1208                         return;
1209                 }
1210         }
1211 }
1212
1213 void Floor::RemoveTrigger(Trigger *trigger)
1214 {
1215         //remove a trigger reference (does not delete the object itself)
1216         for (int i = 0; i < (int)TriggerArray.size(); i++)
1217         {
1218                 if (TriggerArray[i] == trigger)
1219                 {
1220                         TriggerArray.erase(TriggerArray.begin() + i);
1221                         return;
1222                 }
1223         }
1224 }
1225
1226 void Floor::RemoveCameraTexture(CameraTexture *cameratexture)
1227 {
1228         //remove a camera texture reference (does not delete the object itself)
1229         for (int i = 0; i < (int)CameraTextureArray.size(); i++)
1230         {
1231                 if (CameraTextureArray[i] == cameratexture)
1232                 {
1233                         CameraTextureArray.erase(CameraTextureArray.begin() + i);
1234                         return;
1235                 }
1236         }
1237 }
1238
1239 Object* Floor::AddLight(const char *name, int type, Ogre::Vector3 position, Ogre::Vector3 direction, float color_r, float color_g, float color_b, float spec_color_r, float spec_color_g, float spec_color_b, float spot_inner_angle, float spot_outer_angle, float spot_falloff, float att_range, float att_constant, float att_linear, float att_quadratic)
1240 {
1241         //add a light
1242
1243         Light* light = new Light(this, name, type, position + Ogre::Vector3(0, GetBase(true), 0), direction, color_r, color_g, color_b, spec_color_r, spec_color_g, spec_color_b, spot_inner_angle, spot_outer_angle, spot_falloff, att_range, att_constant, att_linear, att_quadratic);
1244         lights.push_back(light);
1245         return light;
1246 }
1247
1248 Object* Floor::AddModel(const char *name, const char *filename, bool center, Ogre::Vector3 position, Ogre::Vector3 rotation, float max_render_distance, float scale_multiplier, bool enable_physics, float restitution, float friction, float mass)
1249 {
1250         //add a model
1251         Model* model = new Model(this, name, filename, center, position + Ogre::Vector3(0, GetBase(true), 0), rotation, max_render_distance, scale_multiplier, enable_physics, restitution, friction, mass);
1252         if (model->load_error == true)
1253         {
1254                 delete model;
1255                 return 0;
1256         }
1257         ModelArray.push_back(model);
1258         return model;
1259 }
1260
1261 void Floor::ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
1262 {
1263         //change all instances of oldtexture in all meshes to newtexture
1264         Level->ReplaceTexture(oldtexture, newtexture);
1265         Interfloor->ReplaceTexture(oldtexture, newtexture);
1266         ColumnFrame->ReplaceTexture(oldtexture, newtexture);
1267 }
1268
1269 Object* Floor::AddControl(const char *name, const char *sound, const char *direction, float CenterX, float CenterZ, float width, float height, float voffset, std::vector<std::string> &action_names, std::vector<std::string> &textures)
1270 {
1271         //add a control
1272         std::vector<Action*> actionnull; //not used
1273         Control* control = new Control(this, name, false, sound, action_names, actionnull, textures, direction, width, height, true);
1274         control->Move(CenterX, GetBase(true) + voffset, CenterZ);
1275         ControlArray.push_back(control);
1276         return control;
1277 }
1278
1279 Object* Floor::AddTrigger(const char *name, const char *sound_file, Ogre::Vector3 &area_min, Ogre::Vector3 &area_max, std::vector<std::string> &action_names)
1280 {
1281         //add a trigger
1282         Trigger* trigger = new Trigger(this, name, false, sound_file, area_min, area_max, action_names);
1283         TriggerArray.push_back(trigger);
1284         trigger->Move(0, GetBase(true), 0);
1285         return trigger;
1286 }
1287
1288 Object* Floor::AddCameraTexture(const char *name, bool enabled, int quality, float fov, Ogre::Vector3 position, bool use_rotation, Ogre::Vector3 rotation)
1289 {
1290         //add a camera texture
1291         CameraTexture* cameratexture = new CameraTexture(this, name, enabled, quality, fov, GetBase(true) + position, use_rotation, rotation);
1292         CameraTextureArray.push_back(cameratexture);
1293         return cameratexture;
1294 }
1295
1296 Object* Floor::AddEscalator(const char *name, const char *texture, const char *direction, float CenterX, float CenterZ, float width, float risersize, float treadsize, int num_steps, float voffset, float tw, float th)
1297 {
1298         //add an escalator
1299         Escalator* escalator = new Escalator(this, name, texture, direction, CenterX, CenterZ, width, risersize, treadsize, num_steps, GetBase(true) + voffset, tw, th);
1300         EscalatorArray.push_back(escalator);
1301         return escalator;
1302 }
1303
1304 void Floor::SetAltitude(float altitude)
1305 {
1306         //position object at altitude
1307         SetPositionY(altitude);
1308         Altitude = altitude;
1309 }
1310
1311 void Floor::ShowInfo(bool detailed, bool display_header)
1312 {
1313         //show information about this floor on the console
1314
1315         //if detailed is true (default), show detailed information for this floor
1316         //otherwise, show a single-line listing suitable for showing in a list with other floors
1317
1318         //if display_header is true, show header/key along with listing
1319
1320         if (display_header == true)
1321                 sbs->Report("\n--- Floor Information ---\n");
1322
1323         if (detailed == true)
1324         {
1325                 sbs->Report("Number: " + ToString2(Number));
1326                 sbs->Report("ID: " + ID);
1327                 sbs->Report("Name: " + Name);
1328                 sbs->Report("Type: " + FloorType);
1329                 sbs->Report("Description: " + Description);
1330                 sbs->Report("Height: " + ToString2(Height));
1331                 sbs->Report("InterfloorHeight: " + ToString2(InterfloorHeight));
1332                 sbs->Report("FullHeight: " + ToString2(FullHeight()));
1333                 sbs->Report("Altitude: " + ToString2(Altitude));
1334                 sbs->Report("Base: " + ToString2(GetBase()));
1335
1336                 std::vector<int> elevator_list, stairs_list, shaft_list;
1337                 GetElevatorList(elevator_list);
1338                 GetStairsList(stairs_list);
1339                 GetShaftList(shaft_list);
1340
1341                 std::string elevs;
1342                 for (int i = 0; i < (int)elevator_list.size(); i++)
1343                 {
1344                         elevs += ToString2(elevator_list[i]);
1345                         if (i < (int)elevator_list.size() - 1)
1346                                 elevs += ", ";
1347                 }
1348                 sbs->Report("Elevators servicing: " + elevs);
1349
1350                 std::string stairs;
1351                 for (int i = 0; i < (int)stairs_list.size(); i++)
1352                 {
1353                         stairs += ToString2(stairs_list[i]);
1354                         if (i < (int)stairs_list.size() - 1)
1355                                 stairs += ", ";
1356                 }
1357                 sbs->Report("Stairwells spanning: " + stairs);
1358
1359                 std::string shafts;
1360                 for (int i = 0; i < (int)shaft_list.size(); i++)
1361                 {
1362                         shafts += ToString2(shaft_list[i]);
1363                         if (i < (int)shaft_list.size() - 1)
1364                                 shafts += ", ";
1365                 }
1366                 sbs->Report("Shafts spanning: " + shafts);
1367
1368                 if (display_header == true)
1369                         sbs->Report("");
1370         }
1371         else
1372         {
1373                 if (display_header == true)
1374                         sbs->Report("Number(ID)\t----\tName\t----\tType\t----\tHeight\t----\tIFloorHeight\t----\tAltitude\t----\tBase\t----\tDescription");
1375
1376                 sbs->Report(ToString2(Number) + "(" + ID + ")\t----\t" + Name + "\t----\t" + FloorType + "\t----\t" + ToString2(Height) + "\t----\t" + ToString2(InterfloorHeight) + "\t----\t" + ToString2(Altitude) + "\t----\t" + ToString2(GetBase()) + "\t----\t" + Description);
1377         }
1378 }
1379
1380 void Floor::GetElevatorList(std::vector<int> &listing)
1381 {
1382         //return a list of elevators that service this floor
1383
1384         for (int i = 1; i <= sbs->Elevators(); i++)
1385         {
1386                 Elevator *elev = sbs->GetElevator(i);
1387                 if (elev)
1388                 {
1389                         if (elev->IsServicedFloor(Number) == true)
1390                                 listing.push_back(elev->Number);
1391                 }
1392         }
1393 }
1394
1395 void Floor::GetStairsList(std::vector<int> &listing)
1396 {
1397         //return a list of stairwells that span this floor
1398
1399         for (int i = 1; i <= sbs->StairsNum(); i++)
1400         {
1401                 Stairs *stairs = sbs->GetStairs(i);
1402                 if (stairs)
1403                 {
1404                         if (stairs->IsValidFloor(Number) == true)
1405                                 listing.push_back(stairs->StairsNum);
1406                 }
1407         }
1408 }
1409
1410 void Floor::GetShaftList(std::vector<int> &listing)
1411 {
1412         //return a list of shafts that span this floor
1413
1414         for (int i = 1; i <= sbs->Shafts(); i++)
1415         {
1416                 Shaft *shaft = sbs->GetShaft(i);
1417                 if (shaft)
1418                 {
1419                         if (shaft->IsValidFloor(Number) == true)
1420                                 listing.push_back(shaft->ShaftNumber);
1421                 }
1422         }
1423 }