4 Scalable Building Simulator - Core
5 The Skyscraper Project - Version 1.11 Alpha
6 Copyright (C)2004-2016 Ryan Thoryk
7 http://www.skyscrapersim.com
8 http://sourceforge.net/projects/skyscraper
9 Contact - ryan@skyscrapersim.com
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.
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.
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.
27 #include <OgreSceneManager.h>
28 #include <OgreFileSystem.h>
29 #include <OgreConfigFile.h>
30 #include <OgreTimer.h>
31 #include "OgreStringVector.h"
33 #include <OgreBulletDynamicsRigidBody.h>
34 #include <OgreBulletCollisionsRay.h>
39 #include "dynamicmesh.h"
43 #include "elevatorcar.h"
44 #include "elevatordoor.h"
50 #include "escalator.h"
54 #include "callbutton.h"
57 #include "soundsystem.h"
67 SBS::SBS(Ogre::SceneManager* mSceneManager, FMOD::System *fmodsystem, int instance_number, const Ogre::Vector3 &position, float rotation, const Ogre::Vector3 &area_min, const Ogre::Vector3 &area_max) : Object(0)
70 this->mSceneManager = mSceneManager;
72 version = "0.11.0." + std::string(SVN_REVSTR);
73 version_state = "Alpha";
75 //root object needs to self-register
78 InstanceNumber = instance_number;
81 SetValues("SBS", "SBS", true);
83 mRoot = Ogre::Root::getSingletonPtr();
86 configfile = new Ogre::ConfigFile();
87 configfile->load("skyscraper.ini");
89 //initialize variables
91 BuildingDesigner = "";
92 BuildingLocation = "";
93 BuildingDescription = "";
101 IsBuildingsEnabled = false;
102 IsExternalEnabled = false;
103 IsLandscapeEnabled = false;
104 IsSkyboxEnabled = false;
109 FrameLimiter = false;
110 AutoShafts = GetConfigBool("Skyscraper.SBS.AutoShafts", true);
111 AutoStairs = GetConfigBool("Skyscraper.SBS.AutoStairs", true);
112 ElevatorSync = false;
115 wall_orientation = 1;
116 floor_orientation = 2;
125 DrawSideNOld = false;
126 DrawSidePOld = false;
128 DrawBottomOld = false;
134 ProcessElevators = GetConfigBool("Skyscraper.SBS.ProcessElevators", true);
139 DeleteColliders = false;
141 UnitScale = GetConfigFloat("Skyscraper.SBS.UnitScale", 4);
142 Verbose = GetConfigBool("Skyscraper.SBS.Verbose", false);
143 InterfloorOnTop = false;
152 current_virtual_time = 0;
155 timer = new Ogre::Timer();
162 TexelOverride = false;
163 enable_profiling = false;
164 enable_advanced_profiling = false;
165 SkyName = GetConfigString("Skyscraper.SBS.SkyName", "noon");
166 ShaftDisplayRange = GetConfigInt("Skyscraper.SBS.ShaftDisplayRange", 3);
167 StairsDisplayRange = GetConfigInt("Skyscraper.SBS.StairsDisplayRange", 5);
168 ShaftOutsideDisplayRange = GetConfigInt("Skyscraper.SBS.ShaftOutsideDisplayRange", 3);
169 StairsOutsideDisplayRange = GetConfigInt("Skyscraper.SBS.StairsOutsideDisplayRange", 3);
170 FloorDisplayRange = GetConfigInt("Skyscraper.SBS.FloorDisplayRange", 3);
171 SmoothFrames = GetConfigInt("Skyscraper.SBS.SmoothFrames", 200);
172 RenderOnStartup = GetConfigBool("Skyscraper.SBS.RenderOnStartup", false);
174 RandomActivity = GetConfigBool("Skyscraper.SBS.RandomActivity", false);
191 //add instance number to reports
192 InstancePrompt = ToString(InstanceNumber) + "> ";
194 //move to specified position
198 Rotate(0.0f, rotation, 0.0f);
200 //create main engine area trigger
201 SetBounds(area_min, area_max);
203 //create sound system object if sound is enabled
205 soundsystem = new SoundSystem(this, fmodsystem);
208 void SBS::Initialize()
210 //create texture manager
211 texturemanager = new TextureManager(this);
214 Ogre::AxisAlignedBox box (Ogre::Vector3::ZERO, Ogre::Vector3::ZERO);
215 mWorld = new OgreBulletDynamics::DynamicsWorld(mSceneManager, box, Ogre::Vector3::ZERO, true);
216 mWorld->setAllowedCcdPenetration(0);
218 /*debugDrawer = new OgreBulletCollisions::DebugDrawer();
219 debugDrawer->setDrawWireframe(true);
220 mWorld->setDebugDrawer(debugDrawer);
221 Ogre::SceneNode *node = mSceneManager->getRootSceneNode()->createChildSceneNode("debugDrawer", Ogre::Vector3::ZERO);
222 node->attachObject(static_cast<Ogre::SimpleRenderable*> (debugDrawer));
225 //mount sign texture packs
226 Mount("signs-sans.zip", "signs/sans");
227 Mount("signs-sans_bold.zip", "signs/sans_bold");
228 Mount("signs-sans_cond.zip", "signs/sans_cond");
229 Mount("signs-sans_cond_bold.zip", "signs/sans_cond_bold");
231 //create object meshes
232 Buildings = new MeshObject(this, "Buildings");
233 External = new MeshObject(this, "External");
234 Landscape = new MeshObject(this, "Landscape");
235 //Landscape->tricollider = false;
237 //create manager objects
238 floor_manager = new FloorManager(this);
239 elevator_manager = new ElevatorManager(this);
240 shaft_manager = new ShaftManager(this);
241 stairs_manager = new StairsManager(this);
242 door_manager = new DoorManager(this);
243 revolvingdoor_manager = new RevolvingDoorManager(this);
245 //create camera object
246 this->camera = new Camera(this);
253 Report("Deleting simulator objects...");
258 for (size_t i = 0; i < PersonArray.size(); i++)
262 PersonArray[i]->parent_deleting = true;
263 delete PersonArray[i];
269 for (size_t i = 0; i < ControlArray.size(); i++)
273 ControlArray[i]->parent_deleting = true;
274 delete ControlArray[i];
280 for (size_t i = 0; i < TriggerArray.size(); i++)
284 TriggerArray[i]->parent_deleting = true;
285 delete TriggerArray[i];
291 for (size_t i = 0; i < ModelArray.size(); i++)
295 ModelArray[i]->parent_deleting = true;
296 delete ModelArray[i];
302 for (size_t i = 0; i < lights.size(); i++)
306 lights[i]->parent_deleting = true;
312 //delete camera object
315 camera->parent_deleting = true;
320 //delete manager objects
322 delete floor_manager;
325 if (elevator_manager)
326 delete elevator_manager;
327 elevator_manager = 0;
330 delete shaft_manager;
334 delete stairs_manager;
341 if (revolvingdoor_manager)
342 delete revolvingdoor_manager;
343 revolvingdoor_manager = 0;
346 for (size_t i = 0; i < sounds.size(); i++)
350 sounds[i]->parent_deleting = true;
357 for (size_t i = 0; i < ActionArray.size(); i++)
360 delete ActionArray[i];
364 //delete mesh objects
367 SkyBox->parent_deleting = true;
374 Landscape->parent_deleting = true;
381 External->parent_deleting = true;
388 Buildings->parent_deleting = true;
393 //delete sound system
398 //delete texture manager
400 delete texturemanager;
403 //delete main area trigger
408 //delete physics objects
411 //delete mWorld->getDebugDrawer();
412 //mWorld->setDebugDrawer(0);
418 verify_results.clear();
428 //clear self reference
434 bool SBS::Start(Ogre::Camera *camera)
436 //Post-init startup code goes here, before the runloop
438 //prepare 3D geometry for use
441 //free text texture memory
442 texturemanager->FreeTextureBoxes();
444 //reset building state
447 //initialize objects (cascades down through entire object tree)
450 //play looping global sounds
451 for (size_t i = 0; i < sounds.size(); i++)
455 if (sounds[i]->GetLoopState() == true)
460 //attach camera object
461 AttachCamera(camera);
464 sbs->GetElevatorManager()->EnableAll(true);
466 //enable random activity if specified
467 if (RandomActivity == true)
468 EnableRandomActivity(true);
475 void SBS::PrintBanner()
478 Report(" Scalable Building Simulator " + version + " " + version_state);
479 Report(" Copyright (C)2004-2016 Ryan Thoryk");
480 Report(" This software comes with ABSOLUTELY NO WARRANTY. This is free");
481 Report(" software, and you are welcome to redistribute it under certain");
482 Report(" conditions. For details, see the file gpl.txt\n");
487 //Main simulator loop
488 SBS_PROFILE("SBS::Loop");
490 //This makes sure all timer steps are the same size, in order to prevent the physics from changing
491 //depending on frame rate
493 unsigned long timing;
495 if (SmoothFrames > 0)
496 timing = GetAverageTime();
498 timing = GetElapsedTime();
500 float elapsed = float(timing) / 1000.0f;
502 //calculate start and running time
504 start_time = GetRunTime() / 1000.0f;
505 running_time = (GetRunTime() / 1000.0f) - start_time;
507 //move camera or update character movement
508 camera->MoveCharacter();
511 if (camera->EnableBullet == true)
513 if (enable_advanced_profiling == false)
514 ProfileManager::Start_Profile("Collisions/Physics");
516 ProfileManager::Start_Profile("Bullet");
517 mWorld->stepSimulation(elapsed, 0);
518 ProfileManager::Stop_Profile();
521 //sync camera to physics
528 elapsed += remaining_delta;
530 //limit the elapsed value to prevent major slowdowns during debugging
534 ProfileManager::Start_Profile("Simulator Loop");
535 while (elapsed >= delta)
537 //Determine floor that the camera is on
538 camera->UpdateCameraFloor();
540 //process child object dynamic runloops
543 camera->CheckObjects();
550 remaining_delta = elapsed;
555 //process engine boundary trigger
557 area_trigger->Loop();
559 ProfileManager::Stop_Profile();
561 //process camera loop
565 void SBS::CalculateFrameRate()
567 //calculate frame rate
568 fps_tottime += elapsed_time;
570 if (fps_tottime > 500)
572 FPS = (float (fps_frame_count) * 1000.0f) / float (fps_tottime);
578 bool SBS::AddWallMain(Object *parent, MeshObject* mesh, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float height_in1, float height_in2, float altitude1, float altitude2, float tw, float th, bool autosize)
580 Wall *object = new Wall(mesh, parent, true);
581 bool result = AddWallMain(object, name, texture, thickness, x1, z1, x2, z2, height_in1, height_in2, altitude1, altitude2, tw, th, autosize);
586 bool SBS::AddWallMain(Wall* wallobject, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float height_in1, float height_in2, float altitude1, float altitude2, float tw, float th, bool autosize)
588 //Adds a wall with the specified dimensions
590 //exit if coordinates are invalid
591 if (x1 == x2 && z1 == z2)
592 return ReportError("Invalid coordinates for wall '" + name + "'");
594 if (height_in1 == 0.0f && height_in2 == 0.0f)
595 return ReportError("No wall height specified for wall '" + name + "'");
597 //determine axis of wall
599 if (std::abs(x1 - x2) > (std::abs(z1 - z2) + 0.00001))
606 //convert to clockwise coordinates if on x-axis, or counterclockwise if on z-axis
607 if ((x1 > x2 && axis == 1) || (z1 < z2 && axis == 2))
609 //reverse coordinates
612 Swap(altitude1, altitude2);
613 Swap(height_in1, height_in2);
617 Ogre::Vector3 v1 (x1, altitude1 + height_in1, z1); //left top
618 Ogre::Vector3 v2 (x2, altitude2 + height_in2, z2); //right top
619 Ogre::Vector3 v3 (x2, altitude2, z2); //right base
620 Ogre::Vector3 v4 (x1, altitude1, z1); //left base
622 Ogre::Vector3 v5 = v1;
623 Ogre::Vector3 v6 = v2;
624 Ogre::Vector3 v7 = v3;
625 Ogre::Vector3 v8 = v4;
627 //exit if outside of the engine boundaries
630 Ogre::Vector3 v1x = wallobject->GetMesh()->GetPosition() + v1;
631 Ogre::Vector3 v2x = wallobject->GetMesh()->GetPosition() + v3;
632 if (area_trigger->IsOutside(v1x, v2x) == true)
636 //expand to specified thickness
640 if (wall_orientation == 0)
648 if (wall_orientation == 1)
651 float half = thickness / 2;
661 if (wall_orientation == 2)
673 if (wall_orientation == 0)
681 if (wall_orientation == 1)
684 float half = thickness / 2;
694 if (wall_orientation == 2)
704 //create polygons and set names
705 std::string NewName, texture2 = texture;
706 float tw2 = tw, th2 = th;
708 bool FlipTexture = texturemanager->FlipTexture;
709 bool TextureOverride = texturemanager->TextureOverride;
711 if (FlipTexture == true)
712 texturemanager->ProcessTextureFlip(tw, th);
714 if (DrawMainN == true)
716 if (FlipTexture == true)
718 tw2 = texturemanager->widthscale[0];
719 th2 = texturemanager->heightscale[0];
721 if (TextureOverride == true)
722 texture2 = texturemanager->mainnegtex;
725 if (GetDrawWallsCount() > 1)
726 NewName.append(":front");
727 wallobject->AddQuad(NewName, texture2, v1, v2, v3, v4, tw2, th2, autosize); //front wall
730 if (DrawMainP == true)
732 if (FlipTexture == true)
734 tw2 = texturemanager->widthscale[1];
735 th2 = texturemanager->heightscale[1];
737 if (TextureOverride == true)
738 texture2 = texturemanager->mainpostex;
741 NewName.append(":back");
742 wallobject->AddQuad(NewName, texture2, v6, v5, v8, v7, tw2, th2, autosize); //back wall
745 if (thickness != 0.0f)
747 if (DrawSideN == true)
749 if (FlipTexture == true)
751 tw2 = texturemanager->widthscale[2];
752 th2 = texturemanager->heightscale[2];
754 if (TextureOverride == true)
755 texture2 = texturemanager->sidenegtex;
758 NewName.append(":left");
760 wallobject->AddQuad(NewName, texture2, v5, v1, v4, v8, tw2, th2, autosize); //left wall
762 wallobject->AddQuad(NewName, texture2, v2, v6, v7, v3, tw2, th2, autosize); //left wall
765 if (DrawSideP == true)
767 if (FlipTexture == true)
769 tw2 = texturemanager->widthscale[3];
770 th2 = texturemanager->heightscale[3];
772 if (TextureOverride == true)
773 texture2 = texturemanager->sidepostex;
776 NewName.append(":right");
778 wallobject->AddQuad(NewName, texture2, v2, v6, v7, v3, tw2, th2, autosize); //right wall
780 wallobject->AddQuad(NewName, texture2, v5, v1, v4, v8, tw2, th2, autosize); //right wall
785 if (FlipTexture == true)
787 tw2 = texturemanager->widthscale[4];
788 th2 = texturemanager->heightscale[4];
790 if (TextureOverride == true)
791 texture2 = texturemanager->toptex;
794 NewName.append(":top");
795 wallobject->AddQuad(NewName, texture2, v5, v6, v2, v1, tw2, th2, autosize); //top wall
798 if (DrawBottom == true)
800 if (FlipTexture == true)
802 tw2 = texturemanager->widthscale[5];
803 th2 = texturemanager->heightscale[5];
805 if (TextureOverride == true)
806 texture2 = texturemanager->bottomtex;
809 NewName.append(":bottom");
810 wallobject->AddQuad(NewName, texture2, v4, v3, v7, v8, tw2, th2, autosize); //bottom wall
817 bool SBS::AddFloorMain(Object *parent, MeshObject* mesh, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float altitude1, float altitude2, bool reverse_axis, bool texture_direction, float tw, float th, bool autosize, bool legacy_behavior)
819 Wall *object = new Wall(mesh, parent, true);
820 bool result = AddFloorMain(object, name, texture, thickness, x1, z1, x2, z2, altitude1, altitude2, reverse_axis, texture_direction, tw, th, autosize, legacy_behavior);
825 bool SBS::AddFloorMain(Wall* wallobject, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float altitude1, float altitude2, bool reverse_axis, bool texture_direction, float tw, float th, bool autosize, bool legacy_behavior)
827 //Adds a floor with the specified dimensions and vertical offset
829 //direction determines the direction of slope (for different altitude values):
830 //false - left/right from altitude1 to altitude2, or legacy (broken) "ReverseAxis = false" behavior if legacy_behavior is true
831 //true - back/forwards from altitude1 to altitude2, or legacy (broken) "ReverseAxis = true" behavior if legacy_behavior is true
833 //exit if coordinates are invalid
834 if (x1 == x2 || z1 == z2)
835 return ReportError("Invalid coordinates for floor '" + name + "'");
837 //convert to clockwise coordinates
839 //determine axis of floor
841 if (std::abs(x1 - x2) > (std::abs(z1 - z2) + 0.00001))
848 if (legacy_behavior == false)
856 if (reverse_axis == true)
857 Swap(altitude1, altitude2);
863 if (reverse_axis == false)
864 Swap(altitude1, altitude2);
869 //legacy (broken) behavior, for compatibility with previous versions
871 if ((x1 > x2 && axis == 1) || (z1 > z2 && axis == 2))
873 //reverse coordinates if the difference between x or z coordinates is greater
876 Swap(altitude1, altitude2);
881 Ogre::Vector3 v1, v2, v3, v4;
883 if (reverse_axis == false)
885 v1 = Ogre::Vector3(x1, altitude1, z1); //bottom left
886 v2 = Ogre::Vector3(x2, altitude1, z1); //bottom right
887 v3 = Ogre::Vector3(x2, altitude2, z2); //top right
888 v4 = Ogre::Vector3(x1, altitude2, z2); //top left
892 if (legacy_behavior == true)
894 v1 = Ogre::Vector3(x1, altitude1, z1); //bottom left
895 v2 = Ogre::Vector3(x1, altitude1, z2); //top left
896 v3 = Ogre::Vector3(x2, altitude2, z2); //top right
897 v4 = Ogre::Vector3(x2, altitude2, z1); //bottom right
901 v1 = Ogre::Vector3(x2, altitude2, z1); //bottom right
902 v2 = Ogre::Vector3(x2, altitude2, z2); //top right
903 v3 = Ogre::Vector3(x1, altitude1, z2); //top left
904 v4 = Ogre::Vector3(x1, altitude1, z1); //bottom left
908 Ogre::Vector3 v5 = v1;
909 Ogre::Vector3 v6 = v2;
910 Ogre::Vector3 v7 = v3;
911 Ogre::Vector3 v8 = v4;
913 //exit if outside of the engine boundaries
916 Ogre::Vector3 v1x = wallobject->GetMesh()->GetPosition() + v1;
917 Ogre::Vector3 v2x = wallobject->GetMesh()->GetPosition() + v3;
918 if (area_trigger->IsOutside(v1x, v2x) == true)
922 //expand to specified thickness
923 if (floor_orientation == 0)
931 if (floor_orientation == 1)
934 float half = thickness / 2;
944 if (floor_orientation == 2)
953 //create polygons and set names
954 std::string NewName, texture2 = texture;
955 float tw2 = tw, th2 = th;
957 bool FlipTexture = texturemanager->FlipTexture;
958 bool TextureOverride = texturemanager->TextureOverride;
960 if (FlipTexture == true)
961 texturemanager->ProcessTextureFlip(tw, th);
963 //turn on rotation if set
964 bool old_planarrotate = texturemanager->GetPlanarRotate();
965 texturemanager->SetPlanarRotate(texture_direction);
967 if (DrawMainN == true)
969 if (FlipTexture == true)
971 tw2 = texturemanager->widthscale[0];
972 th2 = texturemanager->heightscale[0];
974 if (TextureOverride == true)
975 texture2 = texturemanager->mainnegtex;
978 if (GetDrawWallsCount() > 1)
979 NewName.append(":front");
980 wallobject->AddQuad(NewName, texture2, v1, v2, v3, v4, tw2, th2, autosize); //bottom wall
983 if (DrawMainP == true)
985 if (FlipTexture == true)
987 tw2 = texturemanager->widthscale[1];
988 th2 = texturemanager->heightscale[1];
990 if (TextureOverride == true)
991 texture2 = texturemanager->mainpostex;
994 NewName.append(":back");
995 wallobject->AddQuad(NewName, texture2, v8, v7, v6, v5, tw2, th2, autosize); //top wall
998 if (thickness != 0.0f)
1000 if (DrawSideN == true)
1002 if (FlipTexture == true)
1004 tw2 = texturemanager->widthscale[2];
1005 th2 = texturemanager->heightscale[2];
1007 if (TextureOverride == true)
1008 texture2 = texturemanager->sidenegtex;
1011 NewName.append(":left");
1012 wallobject->AddQuad(NewName, texture2, v8, v5, v1, v4, tw2, th2, autosize); //left wall
1015 if (DrawSideP == true)
1017 if (FlipTexture == true)
1019 tw2 = texturemanager->widthscale[3];
1020 th2 = texturemanager->heightscale[3];
1022 if (TextureOverride == true)
1023 texture2 = texturemanager->sidepostex;
1026 NewName.append(":right");
1027 wallobject->AddQuad(NewName, texture2, v6, v7, v3, v2, tw2, th2, autosize); //right wall
1030 if (DrawTop == true)
1032 if (FlipTexture == true)
1034 tw2 = texturemanager->widthscale[4];
1035 th2 = texturemanager->heightscale[4];
1037 if (TextureOverride == true)
1038 texture2 = texturemanager->toptex;
1041 NewName.append(":top");
1042 wallobject->AddQuad(NewName, texture2, v5, v6, v2, v1, tw2, th2, autosize); //front wall
1045 if (DrawBottom == true)
1047 if (FlipTexture == true)
1049 tw2 = texturemanager->widthscale[5];
1050 th2 = texturemanager->heightscale[5];
1052 if (TextureOverride == true)
1053 texture2 = texturemanager->bottomtex;
1056 NewName.append(":bottom");
1057 wallobject->AddQuad(NewName, texture2, v7, v8, v4, v3, tw2, th2, autosize); //back wall
1061 texturemanager->SetPlanarRotate(old_planarrotate);
1066 void SBS::Report(const std::string &message)
1068 Ogre::LogManager::getSingleton().logMessage(InstancePrompt + message);
1069 LastNotification = message;
1072 bool SBS::ReportError(const std::string &message)
1074 Ogre::LogManager::getSingleton().logMessage(InstancePrompt + message, Ogre::LML_CRITICAL);
1075 LastError = message;
1079 Wall* SBS::CreateWallBox(MeshObject* mesh, const std::string &name, const std::string &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, bool autosize)
1086 //exit if coordinates are invalid
1087 if (x1 == x2 && z1 == z2)
1089 ReportError("Invalid coordinates for wall '" + name + "'");
1093 //create wall object
1094 Wall *wall = mesh->CreateWallObject(name);
1096 bool x_thickness = false, z_thickness = false;
1097 std::string NewName, texture2 = texture;
1104 //swap values if the first is greater than the second
1111 bool TextureOverride = texturemanager->TextureOverride;
1115 //generate a box visible from the inside
1118 NewName.append(":inside");
1120 if (x_thickness == true)
1122 if (TextureOverride == true)
1123 texture2 = texturemanager->mainnegtex;
1125 wall->AddQuad( //front
1128 Ogre::Vector3(x1, voffset, z1),
1129 Ogre::Vector3(x2, voffset, z1),
1130 Ogre::Vector3(x2, voffset + height_in, z1),
1131 Ogre::Vector3(x1, voffset + height_in, z1), tw, th, autosize);
1133 if (TextureOverride == true)
1134 texture2 = texturemanager->mainpostex;
1136 wall->AddQuad( //back
1139 Ogre::Vector3(x2, voffset, z2),
1140 Ogre::Vector3(x1, voffset, z2),
1141 Ogre::Vector3(x1, voffset + height_in, z2),
1142 Ogre::Vector3(x2, voffset + height_in, z2), tw, th, autosize);
1144 if (z_thickness == true)
1146 if (TextureOverride == true)
1147 texture2 = texturemanager->sidepostex;
1149 wall->AddQuad( //right
1152 Ogre::Vector3(x2, voffset, z1),
1153 Ogre::Vector3(x2, voffset, z2),
1154 Ogre::Vector3(x2, voffset + height_in, z2),
1155 Ogre::Vector3(x2, voffset + height_in, z1), tw, th, autosize);
1157 if (TextureOverride == true)
1158 texture2 = texturemanager->sidenegtex;
1160 wall->AddQuad( //left
1163 Ogre::Vector3(x1, voffset, z2),
1164 Ogre::Vector3(x1, voffset, z1),
1165 Ogre::Vector3(x1, voffset + height_in, z1),
1166 Ogre::Vector3(x1, voffset + height_in, z2), tw, th, autosize);
1168 if (x_thickness == true && z_thickness == true)
1172 if (TextureOverride == true)
1173 texture2 = texturemanager->bottomtex;
1175 wall->AddQuad( //bottom
1178 Ogre::Vector3(x1, voffset, z2),
1179 Ogre::Vector3(x2, voffset, z2),
1180 Ogre::Vector3(x2, voffset, z1),
1181 Ogre::Vector3(x1, voffset, z1), tw, th, autosize);
1186 if (TextureOverride == true)
1187 texture2 = texturemanager->toptex;
1189 wall->AddQuad( //top
1192 Ogre::Vector3(x1, voffset + height_in, z1),
1193 Ogre::Vector3(x2, voffset + height_in, z1),
1194 Ogre::Vector3(x2, voffset + height_in, z2),
1195 Ogre::Vector3(x1, voffset + height_in, z2), tw, th, autosize);
1200 if (outside == true)
1203 NewName.append(":outside");
1205 if (x_thickness == true)
1207 if (TextureOverride == true)
1208 texture2 = texturemanager->mainnegtex;
1210 wall->AddQuad( //front
1213 Ogre::Vector3(x1, voffset + height_in, z1),
1214 Ogre::Vector3(x2, voffset + height_in, z1),
1215 Ogre::Vector3(x2, voffset, z1),
1216 Ogre::Vector3(x1, voffset, z1), tw, th, autosize);
1218 if (TextureOverride == true)
1219 texture2 = texturemanager->mainpostex;
1221 wall->AddQuad( //back
1224 Ogre::Vector3(x2, voffset + height_in, z2),
1225 Ogre::Vector3(x1, voffset + height_in, z2),
1226 Ogre::Vector3(x1, voffset, z2),
1227 Ogre::Vector3(x2, voffset, z2), tw, th, autosize);
1229 if (z_thickness == true)
1231 if (TextureOverride == true)
1232 texture2 = texturemanager->sidepostex;
1234 wall->AddQuad( //right
1237 Ogre::Vector3(x2, voffset + height_in, z1),
1238 Ogre::Vector3(x2, voffset + height_in, z2),
1239 Ogre::Vector3(x2, voffset, z2),
1240 Ogre::Vector3(x2, voffset, z1), tw, th, autosize);
1242 if (TextureOverride == true)
1243 texture2 = texturemanager->sidenegtex;
1245 wall->AddQuad( //left
1248 Ogre::Vector3(x1, voffset + height_in, z2),
1249 Ogre::Vector3(x1, voffset + height_in, z1),
1250 Ogre::Vector3(x1, voffset, z1),
1251 Ogre::Vector3(x1, voffset, z2), tw, th, autosize);
1253 if (x_thickness == true && z_thickness == true)
1257 if (TextureOverride == true)
1258 texture2 = texturemanager->bottomtex;
1260 wall->AddQuad( //bottom
1263 Ogre::Vector3(x1, voffset, z1),
1264 Ogre::Vector3(x2, voffset, z1),
1265 Ogre::Vector3(x2, voffset, z2),
1266 Ogre::Vector3(x1, voffset, z2), tw, th, autosize);
1270 if (TextureOverride == true)
1271 texture2 = texturemanager->toptex;
1273 wall->AddQuad( //top
1276 Ogre::Vector3(x1, voffset + height_in, z2),
1277 Ogre::Vector3(x2, voffset + height_in, z2),
1278 Ogre::Vector3(x2, voffset + height_in, z1),
1279 Ogre::Vector3(x1, voffset + height_in, z1), tw, th, autosize);
1286 Wall* SBS::CreateWallBox2(MeshObject* mesh, const std::string &name, const std::string &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, bool autosize)
1288 //create 4 walls from a central point
1290 float x1 = CenterX - (WidthX / 2);
1291 float x2 = CenterX + (WidthX / 2);
1292 float z1 = CenterZ - (LengthZ / 2);
1293 float z2 = CenterZ + (LengthZ / 2);
1295 return CreateWallBox(mesh, name, texture, x1, x2, z1, z2, height_in, voffset, tw, th, inside, outside, top, bottom, autosize);
1298 void SBS::AddPolygon(Wall* wallobject, const std::string &texture, std::vector<Ogre::Vector3> &varray, float tw, float th)
1300 //creates a polygon in the specified wall object
1305 std::vector<Ogre::Vector3> varray1 = varray;
1306 std::vector<Ogre::Vector3> varray2;
1308 //get number of stored vertices
1309 size_t num = varray.size();
1311 //create a second array with reversed vertices
1312 varray2.reserve(num);
1313 for (size_t i = num - 1; i < num; --i)
1314 varray2.push_back(varray1[i]);
1316 //create 2 polygons (front and back) from the vertex array
1318 //get polygon native direction
1319 Ogre::Vector3 direction = GetPolygonDirection(varray1);
1321 //if the polygon is facing right, down or to the back, reverse faces
1322 //to keep the vertices clockwise
1323 std::vector<Ogre::Vector3> tmppoly;
1324 if (direction.x == 1 || direction.y == -1 || direction.z == 1)
1331 std::string name = wallobject->GetName();
1334 if (DrawMainN == true)
1336 std::string NewName = name;
1337 if (DrawMainP == true)
1338 NewName.append(":0");
1339 wallobject->AddPolygon(NewName, texture, varray1, tw, th, true);
1341 if (DrawMainP == true)
1343 std::string NewName = name;
1344 if (DrawMainN == true)
1345 NewName.append(":1");
1346 wallobject->AddPolygon(NewName, texture, varray2, tw, th, true);
1350 Wall* SBS::AddCustomWall(MeshObject* mesh, const std::string &name, const std::string &texture, std::vector<Ogre::Vector3> &varray, float tw, float th)
1352 //Adds a wall from a specified array of 3D vectors
1357 //create wall object
1358 Wall *wall = mesh->CreateWallObject(name);
1360 //create polygon in wall object
1361 AddPolygon(wall, texture, varray, tw, th);
1366 Wall* SBS::AddCustomFloor(MeshObject* mesh, const std::string &name, const std::string &texture, std::vector<Ogre::Vector2> &varray, float altitude, float tw, float th)
1368 //Same as AddCustomWall, with only one altitude value value
1369 std::vector<Ogre::Vector3> varray3;
1371 //set up 3D vertex array
1372 varray3.reserve(varray.size());
1373 for (size_t i = 0; i < varray.size(); i++)
1375 varray3.push_back(Ogre::Vector3(varray[i].x, altitude, varray[i].y));
1378 //pass data on to AddCustomWall function
1379 return AddCustomWall(mesh, name, texture, varray3, tw, th);
1382 Wall* SBS::AddTriangleWall(MeshObject* mesh, const std::string &name, const std::string &texture, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float tw, float th)
1384 //Adds a triangular wall with the specified dimensions
1385 std::vector<Ogre::Vector3> varray;
1387 //set up temporary vertex array
1389 varray.push_back(Ogre::Vector3(x1, y1, z1));
1390 varray.push_back(Ogre::Vector3(x2, y2, z2));
1391 varray.push_back(Ogre::Vector3(x3, y3, z3));
1393 //pass data on to AddCustomWall function
1394 return AddCustomWall(mesh, name, texture, varray, tw, th);
1397 void SBS::EnableBuildings(bool value)
1399 //turns buildings on/off
1400 Buildings->Enabled(value);
1401 IsBuildingsEnabled = value;
1404 void SBS::EnableLandscape(bool value)
1406 //turns landscape on/off
1407 Landscape->Enabled(value);
1408 IsLandscapeEnabled = value;
1411 void SBS::EnableExternal(bool value)
1413 //turns external on/off
1414 External->Enabled(value);
1415 IsExternalEnabled = value;
1418 void SBS::EnableSkybox(bool value)
1420 //turns skybox on/off
1423 SkyBox->Enabled(value);
1424 IsSkyboxEnabled = value;
1427 IsSkyboxEnabled = true;
1430 void SBS::CreateSky()
1434 //only create skybox if first engine instance
1435 if (InstanceNumber > 0)
1438 Mount("sky-" + SkyName + ".zip", "sky");
1442 texturemanager->LoadTexture("sky/up.jpg", "SkyTop", 1, 1, false, false, false, 0);
1443 texturemanager->LoadTexture("sky/down.jpg", "SkyBottom", 1, 1, false, false, false, 0);
1444 texturemanager->LoadTexture("sky/left.jpg", "SkyLeft", 1, 1, false, false, false, 0);
1445 texturemanager->LoadTexture("sky/right.jpg", "SkyRight", 1, 1, false, false, false, 0);
1446 texturemanager->LoadTexture("sky/front.jpg", "SkyFront", 1, 1, false, false, false, 0);
1447 texturemanager->LoadTexture("sky/back.jpg", "SkyBack", 1, 1, false, false, false, 0);
1450 SkyBox = new MeshObject(this, "SkyBox");
1451 SkyBox->no_collider = true;
1453 //create a skybox that extends by default 30 miles (30 * 5280 ft) in each direction
1454 float skysize = GetConfigInt("Skyscraper.SBS.HorizonDistance", 30) * 5280.0f;
1455 texturemanager->ResetTextureMapping(true);
1456 Wall *wall = new Wall(SkyBox, SkyBox, true);
1458 wall->AddQuad( //front
1461 Ogre::Vector3(-skysize, -skysize, -skysize),
1462 Ogre::Vector3(skysize, -skysize, -skysize),
1463 Ogre::Vector3(skysize, skysize, -skysize),
1464 Ogre::Vector3(-skysize, skysize, -skysize), 1, 1, false);
1465 wall->AddQuad( //right
1468 Ogre::Vector3(skysize, -skysize, -skysize),
1469 Ogre::Vector3(skysize, -skysize, skysize),
1470 Ogre::Vector3(skysize, skysize, skysize),
1471 Ogre::Vector3(skysize, skysize, -skysize), 1, 1, false);
1472 wall->AddQuad( //back
1475 Ogre::Vector3(skysize, -skysize, skysize),
1476 Ogre::Vector3(-skysize, -skysize, skysize),
1477 Ogre::Vector3(-skysize, skysize, skysize),
1478 Ogre::Vector3(skysize, skysize, skysize), 1, 1, false);
1479 wall->AddQuad( //left
1482 Ogre::Vector3(-skysize, -skysize, skysize),
1483 Ogre::Vector3(-skysize, -skysize, -skysize),
1484 Ogre::Vector3(-skysize, skysize, -skysize),
1485 Ogre::Vector3(-skysize, skysize, skysize), 1, 1, false);
1486 wall->AddQuad( //bottom
1489 Ogre::Vector3(-skysize, -skysize, skysize),
1490 Ogre::Vector3(skysize, -skysize, skysize),
1491 Ogre::Vector3(skysize, -skysize, -skysize),
1492 Ogre::Vector3(-skysize, -skysize, -skysize), 1, -1, false);
1493 wall->AddQuad( //top
1496 Ogre::Vector3(-skysize, skysize, -skysize),
1497 Ogre::Vector3(skysize, skysize, -skysize),
1498 Ogre::Vector3(skysize, skysize, skysize),
1499 Ogre::Vector3(-skysize, skysize, skysize), -1, -1, false);
1501 texturemanager->ResetTextureMapping();
1505 int SBS::GetFloorNumber(float altitude, int lastfloor, bool checklastfloor)
1507 //Returns floor number located at a specified altitude
1509 if (GetTotalFloors() == 0)
1512 //check to see if altitude is below bottom floor
1513 if (altitude < GetFloor(-Basements)->Altitude)
1516 //if checklastfloor is specified, compare altitude with lastfloor
1517 if (checklastfloor == true && GetFloor(lastfloor))
1519 float lastfloor_altitude = GetFloor(lastfloor)->Altitude;
1520 float upperfloor_altitude;
1521 if (lastfloor < Floors - 1)
1522 upperfloor_altitude = GetFloor(lastfloor + 1)->Altitude;
1524 upperfloor_altitude = GetFloor(lastfloor)->Altitude + GetFloor(lastfloor)->FullHeight();
1526 if (upperfloor_altitude > altitude && lastfloor_altitude <= altitude)
1530 //if altitude is below lastfloor, search downwards; otherwise search upwards
1531 if (altitude < lastfloor_altitude)
1533 for (int i = lastfloor - 1; i >= -Basements; i--)
1535 if (GetFloor(i + 1)->Altitude > altitude && GetFloor(i)->Altitude <= altitude)
1539 else if (altitude >= upperfloor_altitude)
1541 for (int i = lastfloor + 1; i < Floors; i++)
1543 if (GetFloor(i - 1)->Altitude <= altitude && GetFloor(i)->Altitude > altitude)
1545 if (i == Floors - 1 && GetFloor(i)->Altitude <= altitude)
1546 return i; //return top floor if on top
1552 //otherwise do a slow linear search through floors
1553 for (int i = -Basements + 1; i < Floors; i++)
1555 //check to see if altitude is within a floor (between the current floor's base and
1556 //the lower floor's base)
1557 if ((GetFloor(i)->Altitude > altitude) && (GetFloor(i - 1)->Altitude <= altitude))
1559 //check to see if altitude is above top floor's altitude
1560 if ((i == Floors - 1) && (altitude > GetFloor(i)->Altitude))
1566 float SBS::GetDistance(float x1, float x2, float z1, float z2)
1568 //returns the distance between 2 2D vectors
1571 return std::abs(x1 - x2);
1573 return std::abs(z1 - z2);
1574 if ((x1 != x2) && (z2 != x2))
1575 return sqrtf(powf(std::abs(x1 - x2), 2) + powf(std::abs(z1 - z2), 2)); //calculate diagonals
1579 Shaft* SBS::CreateShaft(int number, float CenterX, float CenterZ, int startfloor, int endfloor)
1581 //create a shaft object
1583 return shaft_manager->Create(number, CenterX, CenterZ, startfloor, endfloor);
1586 Stairs* SBS::CreateStairwell(int number, float CenterX, float CenterZ, int startfloor, int endfloor)
1588 //create a stairwell object
1590 return stairs_manager->Create(number, CenterX, CenterZ, startfloor, endfloor);
1593 Elevator* SBS::NewElevator(int number)
1595 //create a new elevator object
1597 return elevator_manager->Create(number);
1600 Floor* SBS::NewFloor(int number)
1602 //create a new floor object
1604 return floor_manager->Create(number);
1607 int SBS::GetElevatorCount()
1609 //return the number of elevators
1610 return elevator_manager->GetCount();
1613 int SBS::GetTotalFloors()
1615 //return the number of floors, including basements
1616 return floor_manager->GetCount();
1619 int SBS::GetShaftCount()
1621 //return the number of shafts
1622 return shaft_manager->GetCount();
1625 int SBS::GetStairsCount()
1627 //return the number of stairs
1628 return stairs_manager->GetCount();
1631 Floor* SBS::GetFloor(int number)
1633 //return pointer to floor object
1635 return floor_manager->Get(number);
1638 Elevator* SBS::GetElevator(int number)
1640 //return pointer to elevator object
1642 return elevator_manager->Get(number);
1645 Shaft* SBS::GetShaft(int number)
1647 //return pointer to shaft object
1649 return shaft_manager->Get(number);
1652 Stairs* SBS::GetStairs(int number)
1654 //return pointer to stairs object
1656 return stairs_manager->Get(number);
1659 bool SBS::SetWallOrientation(std::string direction)
1661 //changes internal wall orientation parameter.
1662 //direction can either be "left" (negative), "center" (0), or "right" (positive).
1663 //default on startup is 1, or center.
1664 //the parameter is used to determine the location of the wall's
1665 //x1/x2 or z1/z2 coordinates in relation to the thickness extents
1667 SetCase(direction, false);
1669 if (direction == "left")
1670 wall_orientation = 0;
1671 else if (direction == "center")
1672 wall_orientation = 1;
1673 else if (direction == "right")
1674 wall_orientation = 2;
1676 return ReportError("SetWallOrientation: Invalid wall orientation");
1680 int SBS::GetWallOrientation()
1682 return wall_orientation;
1685 bool SBS::SetFloorOrientation(std::string direction)
1687 //changes internal floor orientation parameter.
1688 //direction can either be "bottom" (negative), "center" (0), or "top" (positive).
1689 //default on startup is 2, or top.
1690 //the parameter is used to determine the location of the floor's
1691 //x1/x2 or z1/z2 coordinates in relation to the thickness extents
1693 SetCase(direction, false);
1695 if (direction == "bottom")
1696 floor_orientation = 0;
1697 else if (direction == "center")
1698 floor_orientation = 1;
1699 else if (direction == "top")
1700 floor_orientation = 2;
1702 return ReportError("SetFloorOrientation: Invalid floor orientation");
1706 int SBS::GetFloorOrientation()
1708 return floor_orientation;
1711 void SBS::DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
1713 //sets which walls should be drawn
1715 //first backup old parameters
1716 DrawMainNOld = DrawMainN;
1717 DrawMainPOld = DrawMainP;
1718 DrawSideNOld = DrawSideN;
1719 DrawSidePOld = DrawSideP;
1720 DrawTopOld = DrawTop;
1721 DrawBottomOld = DrawBottom;
1723 //now set new parameters
1729 DrawBottom = Bottom;
1732 void SBS::ResetWalls(bool ToDefaults)
1734 //if ToDefaults is true, this resets the DrawWalls data to the defaults.
1735 //if ToDefaults is false, this reverts the DrawWalls data to the previous settings.
1737 if (ToDefaults == true)
1738 DrawWalls(true, true, false, false, false, false);
1740 DrawWalls(DrawMainNOld, DrawMainPOld, DrawSideNOld, DrawSidePOld, DrawTopOld, DrawBottomOld);
1743 int SBS::GetDrawWallsCount()
1745 //gets the number of wall polygons enabled
1749 if (DrawMainN == true)
1751 if (DrawMainP == true)
1753 if (DrawSideN == true)
1755 if (DrawSideP == true)
1757 if (DrawTop == true)
1759 if (DrawBottom == true)
1765 float SBS::MetersToFeet(float meters)
1767 //converts meters to feet
1768 return meters * 3.2808399f;
1771 float SBS::FeetToMeters(float feet)
1773 //converts feet to meters
1774 return feet / 3.2808399f;
1777 Wall* SBS::AddDoorwayWalls(MeshObject* mesh, const std::string &wallname, const std::string &texture, float tw, float th)
1779 //add joining doorway polygons if needed
1784 if (wall1a == true && wall2a == true)
1786 Wall *wall = mesh->CreateWallObject(wallname);
1788 //convert extents to relative positioning
1789 Ogre::Vector2 extents_x = wall_extents_x - wall->GetMesh()->GetPosition().x;
1790 Ogre::Vector2 extents_y = wall_extents_y - wall->GetMesh()->GetPosition().y;
1791 Ogre::Vector2 extents_z = wall_extents_z - wall->GetMesh()->GetPosition().z;
1793 //true if doorway is facing forward/backward
1794 //false if doorway is facing left/right
1795 bool direction = std::abs(extents_x.x - extents_x.y) > std::abs(extents_z.x - extents_z.y);
1797 DrawWalls(false, true, false, false, false, false);
1798 if (direction == true)
1799 AddWallMain(wall, "DoorwayLeft", texture, 0, extents_x.x, extents_z.x, extents_x.x, extents_z.y, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
1801 AddWallMain(wall, "DoorwayLeft", texture, 0, extents_x.x, extents_z.x, extents_x.y, extents_z.x, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
1804 DrawWalls(true, false, false, false, false, false);
1805 if (direction == true)
1806 AddWallMain(wall, "DoorwayRight", texture, 0, extents_x.y, extents_z.x, extents_x.y, extents_z.y, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
1808 AddWallMain(wall, "DoorwayRight", texture, 0, extents_x.x, extents_z.y, extents_x.y, extents_z.y, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
1810 AddFloorMain(wall, "DoorwayTop", texture, 0, extents_x.x, extents_z.x, extents_x.y, extents_z.y, extents_y.y, extents_y.y, false, false, tw, th, true);
1813 ResetDoorwayWalls();
1821 void SBS::ResetDoorwayWalls()
1832 Wall* SBS::AddWall(MeshObject* mesh, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float height_in1, float height_in2, float altitude1, float altitude2, float tw, float th)
1834 //Adds a wall with the specified dimensions, to the specified mesh object
1839 Wall *wall = mesh->CreateWallObject(name);
1841 AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height_in1, height_in2, altitude1, altitude2, tw, th, true);
1845 Wall* SBS::AddFloor(MeshObject* mesh, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float altitude1, float altitude2, bool reverse_axis, bool texture_direction, float tw, float th, bool legacy_behavior)
1847 //Adds a floor with the specified dimensions and vertical offset, to the specified mesh object
1852 Wall *wall = mesh->CreateWallObject(name);
1854 AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, altitude1, altitude2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
1858 Wall* SBS::AddGround(const std::string &name, const std::string &texture, float x1, float z1, float x2, float z2, float altitude, int tile_x, int tile_z)
1860 //Adds ground based on a tiled-floor layout, with the specified dimensions and vertical offset
1861 //this does not support thickness
1863 Ogre::Vector3 v1, v2, v3, v4;
1865 float minx, minz, maxx, maxz;
1867 //get min and max values
1889 Wall *wall = Landscape->CreateWallObject(name);
1891 Report("Creating ground...");
1893 //create polygon tiles
1894 for (float i = minx; i < maxx; i += tile_x)
1898 if (i + tile_x > maxx)
1901 sizex = (float)tile_x;
1903 for (float j = minz; j < maxz; j += tile_z)
1905 if (j + tile_z > maxz)
1908 sizez = (float)tile_z;
1910 DrawWalls(true, true, false, false, false, false);
1911 AddFloorMain(wall, name, texture, 0, i, j, i + sizex, j + sizez, altitude, altitude, false, false, 1, 1, false);
1915 Report("Finished ground");
1919 void SBS::EnableFloorRange(int floor, int range, bool value, bool enablegroups, int shaftnumber, int stairsnumber)
1921 //turn on/off a range of floors
1922 //if range is 3, show shaft on current floor (floor), and 1 floor below and above (3 total floors)
1923 //if range is 1, show only the current floor (floor)
1925 SBS_PROFILE("SBS::EnableFloorRange");
1927 //range must be greater than 0
1931 //range must be an odd number; if it's even, then add 1
1932 if (IsEven(range) == true)
1935 //floor must be valid
1936 if (!IsValidFloor(floor))
1939 int additionalfloors;
1941 additionalfloors = (range - 1) / 2;
1943 additionalfloors = 0;
1948 if (shaftnumber > 0)
1949 shaft = GetShaft(shaftnumber);
1950 if (stairsnumber > 0)
1951 stairs = GetStairs(stairsnumber);
1953 //disable floors 1 floor outside of range, unless part of group
1956 int floorval = floor - additionalfloors - 1;
1957 if (IsValidFloor(floorval) && GetFloor(floor)->IsInGroup(floorval) == false)
1958 GetFloor(floorval)->Enabled(false);
1960 floorval = floor + additionalfloors + 1;
1961 if (IsValidFloor(floorval) && GetFloor(floor)->IsInGroup(floorval) == false)
1962 GetFloor(floorval)->Enabled(false);
1965 //enable floors within range
1966 for (int i = floor - additionalfloors; i <= floor + additionalfloors; i++)
1968 Floor *floorobj = GetFloor(i);
1974 //if a shaft is specified, only show the floor if it is in the related shaft's ShowFloorsList array
1975 if (shaft->ShowFloors > 0)
1977 bool showfloor = shaft->IsShowFloor(i);
1979 if (showfloor == true && value == true)
1981 if (floorobj->IsEnabled == false)
1983 floorobj->Enabled(true);
1984 if (enablegroups == true)
1985 floorobj->EnableGroup(true);
1990 //only disable floor if it hasn't been enabled separately by a related group
1991 if (floorobj->EnabledGroup == true)
1993 //for now check to see if the group floor is a ShowFloor
1994 if (shaft->IsShowFloor(floorobj->EnabledGroup_Floor) == true)
1998 if (floorobj->IsEnabled == true)
2000 floorobj->Enabled(false);
2001 if (enablegroups == true)
2002 floorobj->EnableGroup(false);
2009 //if a stairwell is specified, only show the floor if it is in the related stairwell's ShowFloorsList array
2010 if (stairs->ShowFloors == true)
2012 bool showfloor = stairs->IsShowFloor(i);
2014 if (showfloor == true && value == true)
2016 if (floorobj->IsEnabled == false)
2018 floorobj->Enabled(true);
2019 if (enablegroups == true)
2020 floorobj->EnableGroup(true);
2025 //only disable floor if it hasn't been enabled separately by a related group
2026 if (floorobj->EnabledGroup == true)
2028 //for now check to see if the group floor is a ShowFloor
2029 if (stairs->IsShowFloor(floorobj->EnabledGroup_Floor) == true)
2033 if (floorobj->IsEnabled == true)
2035 floorobj->Enabled(false);
2036 if (enablegroups == true)
2037 floorobj->EnableGroup(false);
2044 floorobj->Enabled(value);
2045 if (enablegroups == true)
2046 floorobj->EnableGroup(value);
2052 bool SBS::RegisterTimerCallback(TimerObject *timer)
2054 //register a timer object for callbacks
2059 for (size_t i = 0; i < timercallbacks.size(); i++)
2061 if (timercallbacks[i] == timer)
2065 //if timer isn't already in the array, add it
2066 timercallbacks.push_back(timer);
2071 bool SBS::UnregisterTimerCallback(TimerObject *timer)
2076 for (size_t i = 0; i < timercallbacks.size(); i++)
2078 //unregister existing call button callback
2079 if (timercallbacks[i] == timer)
2081 timercallbacks.erase(timercallbacks.begin() + i);
2089 void SBS::ProcessTimers()
2091 SBS_PROFILE("SBS::ProcessTimers");
2093 //process all registered timers
2094 for (size_t i = 0; i < timercallbacks.size(); i++)
2096 if (timercallbacks[i])
2097 timercallbacks[i]->Loop();
2101 int SBS::GetTimerCallbackCount()
2103 //return the number of registered call button callbacks
2104 return (int)timercallbacks.size();
2107 bool SBS::Mount(const std::string &filename, const std::string &path)
2109 //mounts a zip file into the virtual filesystem
2111 std::string newfile = "data/" + filename;
2112 std::string file = VerifyFile(newfile);
2114 Report("Mounting " + file + " as path " + path);
2117 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(file, "Zip", path, true);
2119 catch (Ogre::Exception &e)
2121 return ReportError("Error mounting file " + file + "\n" + e.getDescription());
2126 void SBS::AddFloorAutoArea(Ogre::Vector3 start, Ogre::Vector3 end)
2128 //adds an auto area that enables/disables floors
2131 newarea.start = start;
2133 newarea.inside = false;
2134 newarea.camerafloor = 0;
2135 FloorAutoArea.push_back(newarea);
2138 void SBS::CheckAutoAreas()
2140 //check all automatic areas
2142 SBS_PROFILE("SBS::CheckAutoAreas");
2144 Ogre::Vector3 position = camera->GetPosition();
2145 int floor = camera->CurrentFloor;
2147 for (size_t i = 0; i < FloorAutoArea.size(); i++)
2149 //reset inside value if floor changed
2150 if (FloorAutoArea[i].camerafloor != floor)
2151 FloorAutoArea[i].inside = false;
2153 if (InBox(FloorAutoArea[i].start, FloorAutoArea[i].end, position) == true && FloorAutoArea[i].inside == false)
2155 //user moved into box; enable floors
2156 FloorAutoArea[i].inside = true;
2157 FloorAutoArea[i].camerafloor = floor;
2158 if (floor > -Basements)
2160 GetFloor(floor - 1)->Enabled(true);
2161 GetFloor(floor - 1)->EnableGroup(true);
2163 GetFloor(floor)->Enabled(true);
2164 GetFloor(floor)->EnableGroup(true);
2165 if (floor < Floors - 1)
2167 GetFloor(floor + 1)->Enabled(true);
2168 GetFloor(floor + 1)->EnableGroup(true);
2171 if (InBox(FloorAutoArea[i].start, FloorAutoArea[i].end, position) == false && FloorAutoArea[i].inside == true)
2173 //user moved out of box; disable floors except current
2174 FloorAutoArea[i].inside = false;
2175 FloorAutoArea[i].camerafloor = 0;
2176 if (floor > -Basements)
2178 GetFloor(floor - 1)->Enabled(false);
2179 GetFloor(floor - 1)->EnableGroup(false);
2181 if (floor < Floors - 1)
2183 GetFloor(floor + 1)->Enabled(false);
2184 GetFloor(floor + 1)->EnableGroup(false);
2186 GetFloor(floor)->Enabled(true);
2187 GetFloor(floor)->EnableGroup(true);
2192 int SBS::GetMeshCount()
2194 //return total number of mesh objects
2195 return (int)meshes.size();
2198 Sound* SBS::AddSound(const std::string &name, const std::string &filename, const 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, const Ogre::Vector3 &direction)
2200 //create a looping sound object
2201 Sound *sound = new Sound(this, name, false);
2202 sounds.push_back(sound);
2204 //set parameters and play sound
2205 sound->SetPosition(position);
2206 sound->SetDirection(direction);
2207 sound->SetVolume(volume);
2208 sound->SetSpeed(speed);
2209 sound->SetDistances(min_distance, max_distance);
2210 sound->SetDirection(direction);
2211 sound->SetDopplerLevel(doppler_level);
2212 sound->SetConeSettings(cone_inside_angle, cone_outside_angle, cone_outside_volume);
2213 sound->Load(filename);
2214 sound->SetLoopState(loop);
2215 if (loop && IsRunning == true)
2221 std::vector<Sound*> SBS::GetSound(const std::string &name)
2225 std::string findname = name;
2226 SetCase(findname, false);
2227 std::vector<Sound*> soundlist;
2228 for (size_t i = 0; i < sounds.size(); i++)
2232 std::string name2 = sounds[i]->GetName();
2233 SetCase(name2, false);
2234 if (findname == name2)
2235 soundlist.push_back(sounds[i]);
2241 int SBS::GetSoundCount()
2243 //return total number of allocated sounds
2247 void SBS::IncrementSoundCount()
2252 void SBS::DecrementSoundCount()
2257 float SBS::ToLocal(float remote_value)
2259 //convert remote (OGRE) vertex positions to local (SBS) positions
2261 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2262 //this means that all Z values that use this function must be inverted.
2264 return remote_value * UnitScale;
2267 Ogre::Vector2 SBS::ToLocal(const Ogre::Vector2& remote_value)
2269 //convert remote (OGRE) vertex positions to local (SBS) positions
2271 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2272 //this means that all Z values that use this function must be inverted.
2274 return remote_value * UnitScale;
2277 Ogre::Vector3 SBS::ToLocal(const Ogre::Vector3& remote_value, bool rescale, bool flip_z)
2279 //convert remote (OGRE) vertex positions to local (SBS) positions
2280 //also convert Z value to OGRE's right-hand coordinate system
2282 Ogre::Vector3 newvalue;
2283 newvalue.x = remote_value.x;
2284 newvalue.y = remote_value.y;
2287 newvalue.z = -remote_value.z; //flip z value for OGRE's right-hand coordinate system
2289 newvalue.z = remote_value.z;
2291 if (rescale == true)
2292 return newvalue * UnitScale;
2297 float SBS::ToRemote(float local_value)
2299 //convert local (SBS) vertex positions to remote (OGRE) positions
2301 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2302 //this means that all Z values that use this function must be inverted.
2304 return local_value / UnitScale;
2307 Ogre::Vector2 SBS::ToRemote(const Ogre::Vector2& local_value)
2309 //convert local (SBS) vertex positions to remote (OGRE) positions
2311 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2312 //this means that all Z values that use this function must be inverted.
2314 return local_value / UnitScale;
2317 Ogre::Vector3 SBS::ToRemote(const Ogre::Vector3& local_value, bool rescale, bool flip_z)
2319 //convert local (SBS) vertex positions to remote (OGRE) positions
2321 Ogre::Vector3 newvalue;
2322 newvalue.x = local_value.x;
2323 newvalue.y = local_value.y;
2326 newvalue.z = -local_value.z; //flip z value for OGRE's right-hand coordinate system
2328 newvalue.z = local_value.z;
2330 if (rescale == true)
2331 return (newvalue / UnitScale);
2336 int SBS::GetObjectCount()
2338 //return number of registered SBS objects
2342 Object* SBS::GetObject(int number)
2344 //return object pointer from global array
2345 if (number >= 0 && number < (int)ObjectArray.size())
2346 return ObjectArray[number];
2351 int SBS::RegisterObject(Object *object)
2353 //add object to global array
2355 ObjectArray.push_back(object);
2356 return (int)ObjectArray.size() - 1;
2359 bool SBS::UnregisterObject(int number)
2362 //note - this doesn't delete the objects
2364 if (number < (int)ObjectArray.size())
2366 if (ObjectArray[number])
2368 if (ObjectArray[number]->GetNumber() == number)
2370 std::vector<Object*> objects;
2371 objects.push_back(ObjectArray[number]);
2372 RemoveActionParent(objects);
2373 ObjectArray[number] = 0;
2382 bool SBS::IsValidFloor(int floor)
2384 //determine if a floor is valid
2386 if (GetFloor(floor))
2391 std::string SBS::DumpState()
2393 //dump basic simulator state to a string
2395 std::string output = "SBS version: " + version + "\n";
2396 output.append("Instance number: " + ToString(InstanceNumber) + "\n");
2397 output.append("Building Name: " + BuildingName + "\n");
2398 output.append("Building Filename: " + BuildingFilename + "\n");
2399 output.append("Building Version: " + BuildingVersion + "\n");
2400 output.append("InStairwell: ");
2401 output.append(BoolToString(InStairwell));
2402 output.append("\n");
2403 output.append("InElevator: ");
2404 output.append(BoolToString(InElevator));
2405 output.append("\n");
2406 output.append("InShaft: ");
2407 output.append(BoolToString(InShaft));
2408 output.append("\n");
2409 output.append("CameraFloor: ");
2411 output.append(ToString(camera->CurrentFloor));
2412 output.append("\n");
2413 output.append("ElevatorNumber: ");
2414 output.append(ToString(ElevatorNumber));
2415 output.append("\n");
2416 output.append("CarNumber: ");
2417 output.append(ToString(CarNumber));
2418 output.append("\n");
2419 output.append("ElevatorSync: ");
2420 output.append(BoolToString(ElevatorSync));
2421 output.append("\n");
2422 output.append("Running Time: ");
2423 output.append(TruncateNumber(running_time, 2));
2424 output.append("\n");
2425 output.append("BuildingsEnabled: ");
2426 output.append(BoolToString(IsBuildingsEnabled));
2427 output.append("\n");
2428 output.append("ExternalEnabled: ");
2429 output.append(BoolToString(IsExternalEnabled));
2430 output.append("\n");
2431 output.append("LandscapeEnabled: ");
2432 output.append(BoolToString(IsLandscapeEnabled));
2433 output.append("\n");
2434 output.append("SkyboxEnabled: ");
2435 output.append(BoolToString(IsSkyboxEnabled));
2436 output.append("\n");
2437 output.append("Verbose: ");
2438 output.append(BoolToString(Verbose));
2439 output.append("\n");
2440 output.append("InterfloorOnTop: ");
2441 output.append(BoolToString(InterfloorOnTop));
2442 output.append("\n");
2443 output.append("Object Count: ");
2444 output.append(ToString(ObjectCount));
2445 output.append("\n");
2448 output.append("Camera Floor: ");
2449 output.append(ToString(camera->CurrentFloor));
2450 output.append("\n");
2451 output.append("Camera Position: " + TruncateNumber(camera->GetPosition().x, 2) + ", " + TruncateNumber(camera->GetPosition().y, 2) + ", " + TruncateNumber(camera->GetPosition().z, 2) + "\n");
2457 bool SBS::DeleteObject(Object *object)
2459 //object deletion routine
2460 //this should be called to delete a simulator object during runtime
2463 return ReportError("Invalid object");
2465 std::string number = ToString(object->GetNumber());
2466 bool deleted = false;
2468 //don't delete permanent objects
2469 if (object->IsPermanent() == true)
2470 return ReportError("Cannot delete permanent object " + number);
2472 std::string type = object->GetType();
2474 //perform standard delete based on object type
2475 if (type == "Floor")
2477 Floor *floor = static_cast<Floor*>(object);
2479 //make sure no shaft is dependent on this floor
2480 for (int i = 0; i < shaft_manager->GetCount(); i++)
2482 Shaft *shaft = shaft_manager->GetIndex(i);
2485 if (shaft->IsValidFloor(floor->Number) == true)
2486 return ReportError("Cannot delete floor " + ToString(floor->Number) + " - in use by shaft " + ToString(shaft->ShaftNumber));
2490 //make sure no stairwell is dependent on this floor
2491 for (int i = 0; i < stairs_manager->GetCount(); i++)
2493 Stairs *stairs = stairs_manager->GetIndex(i);
2496 if (stairs->IsValidFloor(floor->Number) == true)
2497 return ReportError("Cannot delete floor " + ToString(floor->Number) + " - in use by stairwell " + ToString(stairs->StairsNum));
2501 //restrict deletions to only lowest/highest floors
2502 if (floor->Number >= 0 && GetFloor(floor->Number + 1))
2503 return ReportError("Only the highest floor can be deleted");
2505 if (floor->Number < 0 && GetFloor(floor->Number - 1))
2506 return ReportError("Only the lowest basement can be deleted");
2510 else if (type == "Elevator")
2512 else if (type == "ButtonPanel")
2514 if (object->GetParent()->GetType() == "ElevatorCar")
2517 else if (type == "CallButton")
2519 else if (type == "DirectionalIndicator")
2521 else if (type == "Door")
2523 else if (type == "RevolvingDoor")
2525 else if (type == "ElevatorDoor")
2527 else if (type == "FloorIndicator")
2529 else if (type == "Shaft")
2531 Shaft *shaft = static_cast<Shaft*>(object);
2533 //make sure no elevator is dependent on this shaft
2534 for (int i = 0; i < elevator_manager->GetCount(); i++)
2536 Elevator *elev = elevator_manager->GetIndex(i);
2539 if (elev->AssignedShaft == shaft->ShaftNumber)
2540 return ReportError("Cannot delete shaft " + ToString(shaft->ShaftNumber) + " - in use by elevator " + ToString(elev->Number));
2546 else if (type == "Sound")
2548 else if (type == "Stairs")
2550 else if (type == "Wall")
2552 Wall *obj = static_cast<Wall*>(object);
2553 obj->DeletePolygons(true);
2556 else if (type == "Model")
2558 else if (type == "Control")
2560 else if (type == "Trigger")
2562 else if (type == "DoorWrapper")
2564 ElevatorDoor::DoorWrapper* wrapper = static_cast<ElevatorDoor::DoorWrapper*>(object);
2565 if (wrapper->IsShaftDoor == false)
2566 return ReportError("Deleting the main elevator door wrapper is not supported yet");
2570 else if (type == "Escalator")
2572 else if (type == "Person")
2574 else if (type == "ElevatorCar")
2576 ElevatorCar *car = static_cast<ElevatorCar*>(object);
2577 if (car->Number != car->GetElevator()->GetCarCount())
2578 return ReportError("Only the highest elevator car can be deleted");
2579 if (car->Number == 1)
2580 return ReportError("Cannot delete the primary elevator car");
2586 if (deleted == true)
2589 camera->ResetCollisions();
2594 bool SBS::DeleteObject(int object)
2596 //delete object by numeric ID
2597 return DeleteObject(GetObject(object));
2600 bool SBS::MoveObject(Object *object, Ogre::Vector3 position, bool relative, bool X, bool Y, bool Z)
2602 //move an object by reference
2603 //if relative is false, the X, Y and Z values determine which position axes should be set
2606 return ReportError("Invalid object");
2608 if (relative == false)
2611 position.x = object->GetPosition().x;
2613 position.y = object->GetPosition().y;
2615 position.z = object->GetPosition().z;
2617 object->SetPosition(position);
2620 object->Move(position);
2625 bool SBS::RotateObject(Object *object, Ogre::Vector3 rotation, float speed, bool relative, bool X, bool Y, bool Z)
2627 //rotate an object by reference
2628 //if relative is false, the X, Y and Z values determine which position axes should be set
2631 return ReportError("Invalid object");
2633 if (relative == true)
2634 object->Rotate(rotation, speed);
2638 rotation.x = object->GetRotation().x;
2640 rotation.y = object->GetRotation().y;
2642 rotation.z = object->GetRotation().z;
2643 object->SetRotation(rotation);
2649 void SBS::RemoveFloor(Floor *floor)
2651 //remove a floor (does not delete the object)
2653 floor_manager->Remove(floor);
2656 void SBS::RemoveElevator(Elevator *elevator)
2658 //remove an elevator (does not delete the object)
2660 elevator_manager->Remove(elevator);
2663 void SBS::RemoveShaft(Shaft *shaft)
2665 //remove a shaft (does not delete the object)
2667 shaft_manager->Remove(shaft);
2670 void SBS::RemoveStairs(Stairs *stairs)
2672 //remove a stairs object (does not delete the object)
2674 stairs_manager->Remove(stairs);
2677 void SBS::RemoveSound(Sound *sound)
2679 //remove a sound from the array
2680 //this does not delete the object
2682 for (size_t i = 0; i < sounds.size(); i++)
2684 if (sounds[i] == sound)
2686 sounds.erase(sounds.begin() + i);
2692 void SBS::RemoveLight(Light *light)
2694 //remove a light reference (does not delete the object itself)
2695 for (size_t i = 0; i < lights.size(); i++)
2697 if (lights[i] == light)
2699 lights.erase(lights.begin() + i);
2705 void SBS::RemoveModel(Model *model)
2707 //remove a model reference (does not delete the object itself)
2708 for (size_t i = 0; i < ModelArray.size(); i++)
2710 if (ModelArray[i] == model)
2712 ModelArray.erase(ModelArray.begin() + i);
2718 void SBS::RemoveControl(Control *control)
2720 //remove a control reference (does not delete the object itself)
2721 for (size_t i = 0; i < ControlArray.size(); i++)
2723 if (ControlArray[i] == control)
2725 ControlArray.erase(ControlArray.begin() + i);
2731 void SBS::RemoveTrigger(Trigger *trigger)
2733 //remove a trigger reference (does not delete the object itself)
2734 for (size_t i = 0; i < TriggerArray.size(); i++)
2736 if (TriggerArray[i] == trigger)
2738 TriggerArray.erase(TriggerArray.begin() + i);
2744 std::string SBS::VerifyFile(const std::string &filename)
2746 bool result = false;
2747 return VerifyFile(filename, result, false);
2750 std::string SBS::VerifyFile(std::string filename, bool &result, bool skip_cache)
2753 //if it exists, return the same filename
2754 //otherwise search the related folder and find a matching filename with a different
2755 //case (fixes case-sensitivity issues mainly on Linux)
2756 //returns the original string if not found
2757 //"result" will return if the file exists or not, but only accurately if skip_cache is true
2759 TrimString(filename);
2760 ReplaceAll(filename, "\\", "/");
2763 //check for a cached result
2764 if (skip_cache == false)
2766 for (size_t i = 0; i < verify_results.size(); i++)
2768 if (verify_results[i].filename == filename)
2769 return verify_results[i].result;
2773 #if OGRE_VERSION >= 0x00010900
2774 Ogre::FileSystemArchive filesystem(".", "FileSystem", false);
2776 Ogre::FileSystemArchive filesystem(".", "FileSystem");
2779 //check for a mount point
2780 Ogre::StringVectorPtr listing;
2781 std::string shortname;
2782 std::string group = GetMountPath(filename, shortname);
2784 if (group == "General")
2786 //for the General group, check the native filesystem
2788 if (filesystem.exists(filename) == true)
2790 //if exact filename exists, cache and exit
2791 CacheFilename(filename, filename);
2796 //otherwise get listing of files to check
2797 if (filesystem_listing.isNull())
2798 filesystem_listing = filesystem.list();
2799 listing = filesystem_listing;
2803 //for other groups, check resource mount points
2805 if (Ogre::ResourceGroupManager::getSingleton().resourceExists(group, shortname) == true)
2807 //if exact filename exists, cache and exit
2808 CacheFilename(filename, filename);
2813 //otherwise get listing of files to check
2814 listing = Ogre::ResourceGroupManager::getSingleton().listResourceNames(group);
2817 //go through file listing, to find a match with a different case
2818 for (size_t i = 0; i < listing->size(); i++)
2820 std::string check = listing->at(i);
2821 std::string checkoriginal = SetCaseCopy(check, false);
2822 std::string checkfile = SetCaseCopy(filename, false);
2823 if (checkoriginal == checkfile)
2825 //if match is found, cache and exit
2826 CacheFilename(filename, check);
2832 //if no match is found, cache original name and exit
2833 CacheFilename(filename, filename);
2837 bool SBS::FileExists(const std::string &filename)
2839 //check to see if the specified file exists
2842 VerifyFile(filename, result, true);
2847 int SBS::GetWallCount()
2849 //return total number of registered walls
2853 int SBS::GetPolygonCount()
2855 //return total number of registered walls
2856 return PolygonCount;
2859 void SBS::Prepare(bool report)
2861 //prepare objects for run
2865 Report("Preparing objects...");
2866 Report("Processing geometry...");
2869 //prepare mesh objects
2870 for (size_t i = 0; i < meshes.size(); i++)
2872 meshes[i]->Prepare();
2875 //process dynamic meshes
2876 for (size_t i = 0; i < dynamic_meshes.size(); i++)
2878 dynamic_meshes[i]->Prepare();
2882 Report("Creating colliders...");
2884 for (size_t i = 0; i < meshes.size(); i++)
2886 if (meshes[i]->tricollider == true)
2887 meshes[i]->CreateCollider();
2889 meshes[i]->CreateBoxCollider();
2893 Report("Finished prepare");
2896 Light* SBS::AddLight(const std::string &name, int type, const Ogre::Vector3 &position, const 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)
2898 //add a global light
2900 Light* light = new Light(this, name, type, position, 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);
2901 lights.push_back(light);
2905 void SBS::AddMeshHandle(MeshObject* handle)
2907 meshes.push_back(handle);
2910 void SBS::DeleteMeshHandle(MeshObject* handle)
2912 for (size_t i = 0; i < meshes.size(); i++)
2914 if (meshes[i] == handle)
2916 meshes.erase(meshes.begin() + i);
2922 MeshObject* SBS::FindMeshObject(const std::string &name)
2924 //find a mesh object by searching for matching wrapper
2925 for (size_t i = 0; i < meshes.size(); i++)
2927 if (meshes[i]->name == name)
2933 Model* SBS::AddModel(const std::string &name, const std::string &filename, bool center, const Ogre::Vector3 &position, const Ogre::Vector3 &rotation, float max_render_distance, float scale_multiplier, bool enable_physics, float restitution, float friction, float mass)
2936 Model* model = new Model(this, name, filename, center, position, rotation, max_render_distance, scale_multiplier, enable_physics, restitution, friction, mass);
2937 if (model->load_error == true)
2942 ModelArray.push_back(model);
2946 void SBS::AddModel(Model *model)
2948 //add a model reference
2953 for (size_t i = 0; i < ModelArray.size(); i++)
2955 if (ModelArray[i] == model)
2959 ModelArray.push_back(model);
2962 int SBS::GetConfigInt(const std::string &key, int default_value)
2964 std::string result = configfile->getSetting(key, "", ToString(default_value));
2965 return ToInt(result);
2968 std::string SBS::GetConfigString(const std::string &key, const std::string &default_value)
2970 return configfile->getSetting(key, "", default_value);
2973 bool SBS::GetConfigBool(const std::string &key, bool default_value)
2975 std::string result = configfile->getSetting(key, "", ToString(default_value));
2976 return ToBool(result);
2979 float SBS::GetConfigFloat(const std::string &key, float default_value)
2981 std::string result = configfile->getSetting(key, "", ToString(default_value));
2982 return ToFloat(result);
2985 bool SBS::InBox(const Ogre::Vector3 &start, const Ogre::Vector3 &end, const Ogre::Vector3 &test)
2987 //determine if a point (test) is inside the box defines by start and end vertices
2989 if (test.x > start.x && test.y > start.y && test.z > start.z && test.x < end.x && test.y < end.y && test.z < end.z)
2994 void SBS::AdvanceClock()
2998 unsigned long last = current_time;
3001 current_time = GetCurrentTime();
3003 last = current_time;
3005 if (current_time < last)
3006 elapsed_time = current_time + ((unsigned long)-1 - last) + 1;
3008 elapsed_time = current_time - last;
3009 current_virtual_time += elapsed_time;
3010 frame_times.push_back(current_time);
3011 CalculateAverageTime();
3014 unsigned long SBS::GetCurrentTime()
3017 return timer->getMilliseconds();
3020 unsigned long SBS::GetRunTime()
3022 //returns simulator run time
3023 return current_virtual_time;
3026 unsigned long SBS::GetElapsedTime()
3028 //returns the actual elapsed time between frames
3029 return elapsed_time;
3032 unsigned long SBS::GetAverageTime()
3034 //returns the average elapsed time between frames
3035 return average_time;
3038 void SBS::CalculateAverageTime()
3040 //calculates the average frame processing time for a specified number of frames
3042 if (frame_times.size() <= 1)
3045 //SmoothFrames is the maximum number of milliseconds to hold timing info
3047 //find oldest time to keep
3048 std::deque<unsigned long>::iterator it = frame_times.begin(), end = frame_times.end() - 2;
3052 if (frame_times.back() - *it > SmoothFrames)
3059 frame_times.erase(frame_times.begin(), it);
3061 //calculate average time
3062 average_time = (frame_times.back() - frame_times.front()) / ((unsigned long)frame_times.size() - 1);
3065 std::string SBS::GetMountPath(std::string filename, std::string &newfilename)
3067 //get mountpoint (resource group) path of given file
3068 //if not found, return "General"
3070 Ogre::StringVector list = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
3071 ReplaceAll(filename, "\\", "/");
3072 newfilename = filename;
3074 for (size_t i = 0; i < list.size(); i++)
3076 if (StartsWith(filename, list[i] + "/") == true)
3078 newfilename = filename.substr(list[i].size() + 1);
3085 void SBS::ShowColliders(bool value)
3090 mWorld->setShowDebugShapes(value);
3091 camera->ShowDebugShape(value);
3093 catch (Ogre::Exception &e)
3095 ReportError("Error enabling/disabling collider shapes\n" + e.getDescription());
3099 void SBS::CacheFilename(const std::string &filename, const std::string &result)
3101 //caches filename information for VerifyFile function
3102 VerifyResult verify;
3103 verify.filename = filename;
3104 verify.result = result;
3105 verify_results.push_back(verify);
3108 void SBS::SetLighting(float red, float green, float blue)
3110 OldAmbientR = AmbientR;
3111 OldAmbientG = AmbientG;
3112 OldAmbientB = AmbientB;
3118 void SBS::ResetLighting()
3120 AmbientR = OldAmbientR;
3121 AmbientG = OldAmbientG;
3122 AmbientB = OldAmbientB;
3125 Control* SBS::AddControl(const std::string &name, const std::string &sound, const std::string &direction, float CenterX, float CenterZ, float width, float height, float voffset, int selection_position, std::vector<std::string> &action_names, std::vector<std::string> &textures)
3128 std::vector<Action*> actionnull; //not used
3129 Control* control = new Control(this, name, false, sound, action_names, actionnull, textures, direction, width, height, true, selection_position);
3130 control->SetPosition(CenterX, voffset, CenterZ);
3131 ControlArray.push_back(control);
3135 Trigger* SBS::AddTrigger(const std::string &name, const std::string &sound_file, const Ogre::Vector3 &area_min, const Ogre::Vector3 &area_max, std::vector<std::string> &action_names)
3138 Trigger* trigger = new Trigger(this, name, false, sound_file, area_min, area_max, action_names);
3139 TriggerArray.push_back(trigger);
3143 Action* SBS::AddAction(const std::string &name, std::vector<Object*> &action_parents, const std::string &command, const std::vector<std::string> ¶meters)
3145 //add a global action
3147 Action *action = new Action(this, name, action_parents, command, parameters);
3148 ActionArray.push_back(action);
3152 Action* SBS::AddAction(const std::string &name, std::vector<Object*> &action_parents, const std::string &command)
3154 //add a global action
3156 Action *action = new Action(this, name, action_parents, command);
3157 ActionArray.push_back(action);
3161 std::vector<Action*> SBS::GetAction(std::string name)
3163 //get action by name
3164 ReplaceAll(name, " ", "");
3165 std::vector<Action*> actionlist;
3166 for (size_t i = 0; i < ActionArray.size(); i++)
3168 std::string actionname = ActionArray[i]->GetName();
3169 ReplaceAll(actionname, " ", "");
3170 if (actionname == name)
3171 actionlist.push_back(ActionArray[i]);
3176 int SBS::GetActionCount()
3178 //get number of registered actions
3179 return (int)ActionArray.size();
3182 bool SBS::AddActionParent(const std::string &name, std::vector<Object*> &parents)
3184 //add parent to actions specified by 'name'
3186 bool result = false;
3187 std::vector<Action*> actionlist = GetAction(name);
3189 for (size_t i = 0; i < actionlist.size(); i++)
3191 Action *action = actionlist[i];
3192 for (size_t j = 0; j < parents.size(); j++)
3194 if (action->AddParent(parents[j]))
3201 bool SBS::RemoveActionParent(const std::string &name, std::vector<Object*> &parents)
3203 //remove parent object from actions specified by 'name'
3205 bool result = false;
3206 std::vector<Action*> actionlist = GetAction(name);
3208 for (size_t i = 0; i < actionlist.size(); i++)
3210 Action *action = actionlist[i];
3211 for (size_t j = 0; j < parents.size(); j++)
3213 if (action->RemoveParent(parents[j]))
3220 bool SBS::RemoveActionParent(std::vector<Object*> &parents)
3222 //remove parent object from all action objects
3224 bool result = false;
3225 for (size_t i = 0; i < ActionArray.size(); i++)
3227 Action *action = ActionArray[i];
3228 for (size_t j = 0; j < parents.size(); j++)
3230 if (action->RemoveParent(parents[j]))
3237 bool SBS::RemoveAction(std::string name)
3239 //remove action by name
3241 ReplaceAll(name, " ", "");
3242 bool result = false;
3243 for (size_t i = 0; i < ActionArray.size(); i++)
3247 std::string actionname = ActionArray[i]->GetName();
3248 ReplaceAll(actionname, " ", "");
3249 if (actionname == name)
3251 delete ActionArray[i];
3252 ActionArray.erase(ActionArray.begin() + i);
3261 bool SBS::RemoveAction(Action *action)
3268 bool result = false;
3269 for (size_t i = 0; i < ActionArray.size(); i++)
3271 if (ActionArray[i] == action)
3273 delete ActionArray[i];
3274 ActionArray.erase(ActionArray.begin() + i);
3278 //remove reference to action in all control objects
3279 for (size_t j = 0; j < control_index.size(); j++)
3281 control_index[j]->RemoveAction(action);
3288 Object* SBS::GetObject(std::string name)
3290 //get object by name
3292 ReplaceAll(name, " ", "");
3294 for (size_t i = 0; i < ObjectArray.size(); i++)
3298 std::string tmpname = ObjectArray[i]->GetName();
3299 ReplaceAll(tmpname, " ", "");
3300 if (tmpname == name)
3301 return ObjectArray[i];
3307 std::vector<Object*> SBS::GetObjectRange(const std::string &expression)
3309 //get object by name range expression (ex. "Floors 1 to 3")
3311 std::vector<Object*> objects;
3312 size_t temp = expression.find("to", 0);
3314 //the name 'elevator' matches the previous search - in this case, detect it and undo
3315 size_t temp2 = expression.find("tor", 0);
3321 if (temp > 0 && temp != std::string::npos)
3323 if (expression.substr(0, 6) == "Floors")
3325 else if (expression.substr(0, 9) == "Elevators")
3327 else if (expression.substr(0, 6) == "Shafts")
3329 else if (expression.substr(0, 10) == "Stairwells")
3333 ReportError("GetObjectRange: Invalid object type");
3337 std::string str1 = expression.substr(type.size() + 1, temp - (type.size() + 1));
3338 std::string str2 = expression.substr(temp + 2, expression.length() - (temp + 2));
3341 int RangeL = 0, RangeH = 0;
3342 if (!IsNumeric(str1, RangeL) || !IsNumeric(str2, RangeH))
3344 ReportError("GetObjectRange: Invalid range");
3348 for (size_t i = 0; i < ObjectArray.size(); i++)
3352 std::string tmpname = ObjectArray[i]->GetName();
3353 for (int j = RangeL; j <= RangeH; j++)
3355 std::string number = ToString(j);
3356 if (type == "floor")
3358 if (tmpname == "Floor " + number)
3359 objects.push_back(ObjectArray[i]);
3361 if (type == "elevator")
3363 if (tmpname == "Elevator " + number)
3364 objects.push_back(ObjectArray[i]);
3366 if (type == "shaft")
3368 if (tmpname == "Shaft " + number)
3369 objects.push_back(ObjectArray[i]);
3371 if (type == "stairwell")
3373 if (tmpname == "Stairwell " + number)
3374 objects.push_back(ObjectArray[i]);
3382 //return single result
3383 Object *obj = GetObject(expression);
3385 objects.push_back(obj);
3391 Action* SBS::GetAction(int index)
3393 if (index >= 0 && index < (int)ActionArray.size())
3394 return ActionArray[index];
3398 bool SBS::RunAction(const std::string &name)
3400 //run action by name - will run multiple actions if the name is the same
3402 std::vector<Action*> actionlist = GetAction(name);
3405 for (size_t i = 0; i < actionlist.size(); i++)
3407 bool result2 = false;
3408 bool hold = false; //not used
3411 result2 = actionlist[i]->DoAction(this, hold);
3413 if (result2 == false)
3419 bool SBS::RunAction(int index)
3421 //run action by index number
3423 Action *action = GetAction(index);
3424 bool hold = false; //not used
3426 return action->DoAction(this, hold);
3430 void SBS::AddKey(int keyid, const std::string &name)
3432 //adds key 'keyid' to the user's keyring
3436 keys.push_back(key);
3438 Report("Added key " + ToString(keyid) + " (" + name + ") to keyring");
3441 bool SBS::CheckKey(int keyid)
3443 //checks to see if the user has the specified key
3445 for (size_t i = 0; i < keys.size(); i++)
3447 if (keys[i].id == keyid)
3453 void SBS::ListKeys()
3457 Report("\n--- Keys ---\n");
3459 for (size_t i = 0; i < keys.size(); i++)
3461 std::string id = ToString(keys[i].id);
3462 Report(id + " - " + keys[i].name);
3467 void SBS::RegisterControl(Control *control)
3469 //add control to index
3470 control_index.push_back(control);
3473 void SBS::UnregisterControl(Control *control)
3475 //remove control from index
3477 for (size_t i = 0; i < control_index.size(); i++)
3479 if (control_index[i] == control)
3481 control_index.erase(control_index.begin() + i);
3487 void SBS::ShowFloorList()
3489 //show floor information for all floors
3491 bool header_shown = false;
3492 for (int i = -Basements; i < Floors; i++)
3494 Floor *floor = GetFloor(i);
3497 if (header_shown == false)
3499 floor->ShowInfo(false, true);
3500 header_shown = true;
3503 floor->ShowInfo(false, false);
3509 void SBS::ShowSceneNodes(bool value)
3511 //show all scene nodes for debugging
3513 mSceneManager->setDisplaySceneNodes(value);
3516 void SBS::ShowBoundingBoxes(bool value)
3518 //show all mesh bounding boxes for debugging
3520 mSceneManager->showBoundingBoxes(value);
3523 void SBS::ListVisibleMeshes()
3525 //list all meshes visible by the main camera
3527 Report("\n--- Visible Dynamic Meshes ---");
3528 Report("Name\t-\tSubmeshes\n");
3533 for (size_t i = 0; i < dynamic_meshes.size(); i++)
3535 for (size_t j = 0; j < dynamic_meshes[i]->GetMeshCount(); j++)
3537 if (camera->IsDynamicMeshVisible(dynamic_meshes[i], (int)j) == true)
3539 submeshes = dynamic_meshes[i]->GetSubMeshCount((int)j);
3540 Report(dynamic_meshes[i]->GetMeshName((int)j) + "\t-\t" + ToString(submeshes));
3546 Report("Total: " + ToString(count) + " meshes, " + ToString(total) + " submeshes");
3550 int SBS::GetEscalatorCount()
3552 //return total number of allocated sounds
3553 return EscalatorCount;
3556 void SBS::IncrementEscalatorCount()
3561 void SBS::DecrementEscalatorCount()
3566 bool SBS::HitBeam(const Ogre::Ray &ray, float max_distance, MeshObject *&mesh, Wall *&wall, Ogre::Vector3 &hit_position)
3568 //use a given ray and distance, and return the nearest hit mesh and if applicable, wall object
3569 //note that the ray's origin and direction need to be in engine-relative values
3571 //create a new ray that has absolute positioning, for engine offsets
3572 Ogre::Ray ray2 (ToRemote(ToGlobal(ToLocal(ray.getOrigin()))), GetOrientation() * ray.getDirection());
3574 //get a collision callback from Bullet
3575 OgreBulletCollisions::CollisionClosestRayResultCallback callback (ray2, mWorld, max_distance);
3577 //check for collision
3578 mWorld->launchRay(callback);
3580 //exit if no collision
3581 if (callback.doesCollide() == false)
3584 //get collided collision object
3585 OgreBulletCollisions::Object* object = callback.getCollidedObject();
3590 //get name of collision object's grandparent scenenode (which is the same name as the mesh object)
3591 std::string meshname = object->getRootNode()->getParentSceneNode()->getName();
3593 //get hit/intersection position
3594 hit_position = ToLocal(callback.getCollisionPoint());
3596 //get associated mesh object
3597 mesh = FindMeshObject(meshname);
3601 //get wall object, if any
3602 Ogre::Vector3 isect;
3603 float distance = 2000000000.;
3604 Ogre::Vector3 normal = Ogre::Vector3::ZERO;
3605 wall = mesh->FindWallIntersect(ray.getOrigin(), ray.getPoint(max_distance), isect, distance, normal);
3610 void SBS::EnableRandomActivity(bool value)
3612 //enable random activity, by creating random people
3616 //create regular people
3617 for (int i = 0; i < GetTotalFloors(); i++)
3619 Person *person = CreatePerson("Random " + ToString(i + 1), 0, false);
3621 //enable random activity on the person
3622 person->EnableRandomActivity(true);
3625 //create a service person
3626 int i = GetTotalFloors();
3627 Person *person = CreatePerson("Random " + ToString(i + 1), 0, true);
3629 //enable random activity on the person
3630 person->EnableRandomActivity(true);
3632 else if (value == false)
3634 for (size_t i = 0; i < PersonArray.size(); i++)
3636 if (PersonArray[i]->IsRandomActivityEnabled() == true)
3638 Person *person = PersonArray[i];
3645 RandomActivity = value;
3648 bool SBS::IsObjectValid(Object *object, std::string type)
3650 //test if an object is valid
3652 if (type == "Floor")
3654 for (int i = 0; i < floor_manager->GetCount(); i++)
3656 if (floor_manager->GetIndex(i) == static_cast<Floor*>(object))
3660 else if (type == "Elevator")
3662 for (int i = 0; i < elevator_manager->GetCount(); i++)
3664 if (elevator_manager->GetIndex(i) == static_cast<Elevator*>(object))
3668 else if (type == "Shaft")
3670 for (int i = 0; i < shaft_manager->GetCount(); i++)
3672 if (shaft_manager->GetIndex(i) == static_cast<Shaft*>(object))
3676 else if (type == "Stairs")
3678 for (int i = 0; i < stairs_manager->GetCount(); i++)
3680 if (stairs_manager->GetIndex(i) == static_cast<Stairs*>(object))
3684 else if (type == "Mesh")
3686 for (size_t i = 0; i < meshes.size(); i++)
3688 if (meshes[i] == static_cast<MeshObject*>(object))
3692 else if (type == "Control")
3694 for (size_t i = 0; i < control_index.size(); i++)
3696 if (control_index[i] == static_cast<Control*>(object))
3701 //do a slow full scan of the object array for all other objects
3702 for (size_t i = 0; i < ObjectArray.size(); i++)
3704 if (ObjectArray[i] == object)
3710 bool SBS::IsActionValid(Action *action)
3712 //test if an action is valid
3714 for (size_t i = 0; i < ActionArray.size(); i++)
3716 if (ActionArray[i] == action)
3722 Person* SBS::CreatePerson(std::string name, int floor, bool service_access)
3728 int number = GetPersonCount() + 1;
3729 name = "Person " + ToString(number);
3731 Person *person = new Person(this, name, floor, service_access);
3732 PersonArray.push_back(person);
3736 void SBS::RemovePerson(Person *person)
3738 //remove a person (does not delete the object)
3740 for (size_t i = 0; i < PersonArray.size(); i++)
3742 if (PersonArray[i] == person)
3744 PersonArray.erase(PersonArray.begin() + i);
3750 bool SBS::AttachCamera(Ogre::Camera *camera, bool init_state)
3753 return this->camera->Attach(camera, init_state);
3757 bool SBS::DetachCamera()
3759 return camera->Detach();
3762 std::string SBS::ProcessFullName(std::string name, int &instance, int &object_number, bool strip_number)
3764 //if given a full object ID name (such as "0:(4)Landscape"),
3765 //return base name and parse out instance number and object number
3767 //if strip_number is false, leave object number identifier in string
3769 //get and strip off engine instance number
3770 size_t index = name.find(":(");
3771 instance = ToInt(name.substr(0, index));
3772 name.erase(name.begin(), name.begin() + index + 1);
3774 //get and optionally strip off object number
3775 index = name.find(")");
3776 object_number = ToInt(name.substr(1, index - 1));
3778 if (strip_number == true)
3779 name.erase(name.begin(), name.begin() + index + 1);
3784 Person* SBS::GetPerson(int number)
3786 if (number < 0 || number > (int)PersonArray.size() - 1)
3789 return PersonArray[number];
3792 bool SBS::IsInside()
3794 //return true if the user is inside the sim engine's area
3797 return area_trigger->IsInside();
3799 //if no trigger is defined, user is always inside the area
3803 bool SBS::IsInside(const Ogre::Vector3 &position)
3805 //return true if the specified position is inside the sim engine's area
3808 return area_trigger->IsInside(position);
3810 //if no trigger is defined, position is always inside the area
3814 bool SBS::GetBounds(Ogre::Vector3 &min, Ogre::Vector3 &max)
3818 min = area_trigger->GetMin();
3819 max = area_trigger->GetMax();
3823 min = Ogre::Vector3::ZERO;
3824 max = Ogre::Vector3::ZERO;
3828 void SBS::CutOutsideBoundaries(bool landscape, bool buildings, bool external, bool floors)
3830 //cut landscape and buildings for engine bounds if needed
3831 //run this function before calling Start()
3836 Report("Cutting outside boundaries...");
3837 Ogre::Vector3 min = area_trigger->GetMin();
3838 Ogre::Vector3 max = area_trigger->GetMax();
3840 if (landscape == true)
3841 Landscape->CutOutsideBounds(min, max, true, true);
3842 if (buildings == true)
3843 Buildings->CutOutsideBounds(min, max, true, true);
3844 if (external == true)
3845 External->CutOutsideBounds(min, max, true, true);
3849 for (int i = 0; i < floor_manager->GetCount(); i++)
3850 floor_manager->GetIndex(i)->Level->CutOutsideBounds(min, max, true, true);
3854 void SBS::CutInsideBoundaries(const Ogre::Vector3 &min, const Ogre::Vector3 &max, bool landscape, bool buildings, bool external, bool floors)
3856 //cut landscape and buildings for specified bounds
3857 //run this function before calling Start()
3859 if (landscape == true)
3860 Landscape->Cut(min, max, true, true);
3861 if (buildings == true)
3862 Buildings->Cut(min, max, true, true);
3863 if (external == true)
3864 External->Cut(min, max, true, true);
3868 for (int i = 0; i < floor_manager->GetCount(); i++)
3869 floor_manager->GetIndex(i)->Level->Cut(min, max, true, true);
3873 void SBS::SetBounds(const Ogre::Vector3 &area_min, const Ogre::Vector3 &area_max)
3875 //don't set bounds if the primary engine
3876 if (InstanceNumber == 0)
3879 if (area_min != Ogre::Vector3::ZERO && area_max != Ogre::Vector3::ZERO && !area_trigger)
3881 std::vector<std::string> names;
3882 names.push_back("Off");
3883 area_trigger = new Trigger(this, "System Boundary", true, "", area_min, area_max, names);
3887 void SBS::ResetState()
3889 //reset building to original state
3891 //turn on main objects
3892 EnableBuildings(true);
3893 EnableLandscape(true);
3894 EnableExternal(true);
3897 //turn off interior objects
3898 floor_manager->EnableAll(false);
3899 shaft_manager->EnableAll(false);
3900 stairs_manager->EnableAll(false);
3901 elevator_manager->EnableAll(false);
3903 //reset camera state
3904 camera->ResetState();
3907 Ogre::Vector3 SBS::ToGlobal(const Ogre::Vector3 &position)
3909 //convert an engine-relative position to a global (scene) position
3911 return (GetOrientation().Inverse() * position) + GetPosition();
3914 Ogre::Vector3 SBS::FromGlobal(const Ogre::Vector3 &position)
3916 //convert a global (scene) position to an engine-relative position
3918 return (GetOrientation() * (position - GetPosition()));
3921 Ogre::Quaternion SBS::ToGlobal(const Ogre::Quaternion &orientation)
3923 //convert an engine-relative orientation (rotation) to a global (scene) orientation
3925 return (GetOrientation() * orientation);
3928 Ogre::Quaternion SBS::FromGlobal(const Ogre::Quaternion &orientation)
3930 //convert a global (scene) orientation (rotation) to an engine-relative orientation
3932 return (GetOrientation().Inverse() * orientation);
3935 Model* SBS::GetModel(std::string name)
3937 //get a model by name
3939 SetCase(name, false);
3941 for (size_t i = 0; i < ModelArray.size(); i++)
3943 if (SetCaseCopy(ModelArray[i]->GetName(), false) == name)
3944 return ModelArray[i];
3950 void SBS::RegisterDynamicMesh(DynamicMesh *dynmesh)
3952 //register a dynamic mesh with the system
3954 dynamic_meshes.push_back(dynmesh);
3957 void SBS::UnregisterDynamicMesh(DynamicMesh *dynmesh)
3959 //unregister a dynamic mesh from the system
3961 for (size_t i = 0; i < dynamic_meshes.size(); i++)
3963 if (dynamic_meshes[i] == dynmesh)
3965 dynamic_meshes.erase(dynamic_meshes.begin() + i);
3971 SoundSystem* SBS::GetSoundSystem()
3976 int SBS::GetPersonCount()
3978 return (int)PersonArray.size();
3981 bool SBS::HasBounds()
3983 return (area_trigger != 0);
3986 FloorManager* SBS::GetFloorManager()
3988 return floor_manager;
3991 ElevatorManager* SBS::GetElevatorManager()
3993 return elevator_manager;
3996 ShaftManager* SBS::GetShaftManager()
3998 return shaft_manager;
4001 StairsManager* SBS::GetStairsManager()
4003 return stairs_manager;
4006 DoorManager* SBS::GetDoorManager()
4008 return door_manager;
4011 TextureManager* SBS::GetTextureManager()
4013 return texturemanager;
4016 RevolvingDoorManager* SBS::GetRevolvingDoorManager()
4018 return revolvingdoor_manager;