OSDN Git Service

Integrated Enabled() function into Object
[skyscrapersim/skyscraper.git] / src / sbs / shaft.cpp
1 /* $Id$ */
2
3 /*
4         Scalable Building Simulator - Shaft Object
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
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 "elevator.h"
30 #include "elevatorcar.h"
31 #include "dynamicmesh.h"
32 #include "mesh.h"
33 #include "sound.h"
34 #include "door.h"
35 #include "model.h"
36 #include "light.h"
37 #include "camera.h"
38 #include "control.h"
39 #include "profiler.h"
40 #include "shaft.h"
41
42 namespace SBS {
43
44 Shaft::Shaft(Object *parent, int number, float CenterX, float CenterZ, int startfloor, int endfloor) : Object(parent)
45 {
46         //creates a shaft in the location specified by CenterX and CenterZ
47         //and that spans the floor range specified by startfloor and endfloor
48
49         //set up SBS object
50         SetValues("Shaft", "", false);
51
52         ShaftNumber = number;
53         this->startfloor = startfloor;
54         this->endfloor = endfloor;
55
56         //make sure start and ending floors are within a valid range
57         if (startfloor < -sbs->Basements)
58                 return;
59         if (endfloor > sbs->Floors - 1)
60                 return;
61
62         InsideShaft = false;
63         IsEnabled = true;
64         top = sbs->GetFloor(endfloor)->Altitude + sbs->GetFloor(endfloor)->FullHeight();
65         bottom = sbs->GetFloor(startfloor)->Altitude;
66         cutstart = 0;
67         cutend = 0;
68         ShowFloors = 0;
69         ShowOutside = false;
70         ShowInterfloors = false;
71         ShowFullShaft = false;
72         EnableCheck = false;
73         lastcheckresult = false;
74         checkfirstrun = true;
75         lastposition = 0;
76         InElevator = false;
77         ShowFloorsFull_Enabled = false;
78
79         std::string name = "Shaft " + ToString(number);
80
81         SetName(name);
82         SetPosition(CenterX, sbs->GetFloor(startfloor)->Altitude, CenterZ);
83
84         dynamic_mesh = new DynamicMesh(this, GetSceneNode(), name);
85
86         ShaftArray.resize(endfloor - startfloor + 1);
87         EnableArray.resize(endfloor - startfloor + 1);
88         DoorArray.resize(endfloor - startfloor + 1);
89         lights.resize(endfloor - startfloor + 1);
90         ModelArray.resize(endfloor - startfloor + 1);
91         ControlArray.resize(endfloor - startfloor + 1);
92         //TriggerArray.resize(endfloor - startfloor + 1);
93
94         for (int i = startfloor; i <= endfloor; i++)
95         {
96                 //Create shaft meshes
97                 ShaftArray[i - startfloor] = new MeshObject(this, name + ":" + ToString(i), dynamic_mesh);
98                 ShaftArray[i - startfloor]->SetPositionY(sbs->GetFloor(i)->Altitude);
99                 EnableArray[i - startfloor] = true;
100         }
101
102         //create a dynamic mesh for doors
103         DoorWrapper = new DynamicMesh(this, GetSceneNode(), GetName() + " Door Container", 0, true);
104
105         //create a dynamic mesh for doors
106         ShaftDoorContainer = new DynamicMesh(this, GetSceneNode(), name + " Shaft Door Container", 0, true);
107
108         EnableLoop(true);
109 }
110
111 Shaft::~Shaft()
112 {
113         //destructor
114
115         //delete controls
116         for (size_t i = 0; i < ControlArray.size(); i++)
117         {
118                 for (size_t j = 0; j < ControlArray[i].size(); j++)
119                 {
120                         if (ControlArray[i][j])
121                         {
122                                 ControlArray[i][j]->parent_deleting = true;
123                                 delete ControlArray[i][j];
124                         }
125                         ControlArray[i][j] = 0;
126                 }
127         }
128
129         //delete triggers
130         /*for (size_t i = 0; i < TriggerArray.size(); i++)
131         {
132                 for (size_t j = 0; j < TriggerArray[i].size(); j++)
133                 {
134                         if (TriggerArray[i][j])
135                         {
136                                 TriggerArray[i][j]->parent_deleting = true;
137                                 delete TriggerArray[i][j];
138                         }
139                         TriggerArray[i][j] = 0;
140                 }
141         }*/
142
143         //delete models
144         for (size_t i = 0; i < ModelArray.size(); i++)
145         {
146                 for (size_t j = 0; j < ModelArray[i].size(); j++)
147                 {
148                         if (ModelArray[i][j])
149                         {
150                                 ModelArray[i][j]->parent_deleting = true;
151                                 delete ModelArray[i][j];
152                         }
153                         ModelArray[i][j] = 0;
154                 }
155         }
156
157         //delete lights
158         for (size_t i = 0; i < lights.size(); i++)
159         {
160                 for (size_t j = 0; j < lights[i].size(); j++)
161                 {
162                         if (lights[i][j])
163                         {
164                                 lights[i][j]->parent_deleting = true;
165                                 delete lights[i][j];
166                         }
167                         lights[i][j] = 0;
168                 }
169         }
170
171         //delete doors
172         for (size_t i = 0; i < DoorArray.size(); i++)
173         {
174                 for (size_t j = 0; j < DoorArray[i].size(); j++)
175                 {
176                         if (DoorArray[i][j])
177                         {
178                                 DoorArray[i][j]->parent_deleting = true;
179                                 delete DoorArray[i][j];
180                         }
181                         DoorArray[i][j] = 0;
182                 }
183         }
184
185         if (DoorWrapper)
186                 delete DoorWrapper;
187         DoorWrapper = 0;
188
189         if (ShaftDoorContainer)
190                 delete ShaftDoorContainer;
191         ShaftDoorContainer = 0;
192
193         //delete mesh array objects
194         for (size_t i = 0; i < ShaftArray.size(); i++)
195         {
196                 if (ShaftArray[i])
197                 {
198                         ShaftArray[i]->parent_deleting = true;
199                         delete ShaftArray[i];
200                 }
201                 ShaftArray[i] = 0;
202         }
203
204         //delete dynamic mesh
205         if (dynamic_mesh)
206                 delete dynamic_mesh;
207         dynamic_mesh = 0;
208
209         //unregister from parent
210         if (sbs->FastDelete == false && parent_deleting == false)
211                 sbs->RemoveShaft(this);
212 }
213
214 Wall* Shaft::AddWall(int floor, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float height1, float height2, float voffset1, float voffset2, float tw, float th)
215 {
216         //exit with an error if floor is invalid
217         if (IsValidFloor(floor) == false)
218         {
219                 ReportError("AddWall: Floor " + ToString(floor) + " out of range");
220                 return 0;
221         }
222
223         Wall *wall = GetMeshObject(floor)->CreateWallObject(name);
224         AddWall(wall, floor, name, texture, thickness, x1, z1, x2, z2, height1, height2, voffset1, voffset2, tw, th);
225         return wall;
226 }
227
228 bool Shaft::AddWall(Wall *wall, int floor, const std::string &name, const std::string &texture, float thickness, float x1, float z1, float x2, float z2, float height1, float height2, float voffset1, float voffset2, float tw, float th)
229 {
230         //exit with an error if floor is invalid
231         if (IsValidFloor(floor) == false)
232                 return ReportError("AddWall: Floor " + ToString(floor) + " out of range");
233
234         return sbs->AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height1, height2, voffset1, voffset2, tw, th, true);
235 }
236
237 Wall* Shaft::AddFloor(int floor, const std::string &name, const std::string &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)
238 {
239         //exit with an error if floor is invalid
240         if (IsValidFloor(floor) == false)
241         {
242                 ReportError("AddFloor: Floor " + ToString(floor) + " out of range");
243                 return 0;
244         }
245
246         Wall *wall = GetMeshObject(floor)->CreateWallObject(name);
247         AddFloor(wall, floor, name, texture, thickness, x1, z1, x2, z2, voffset1, voffset2, reverse_axis, texture_direction, tw, th, legacy_behavior);
248         return wall;
249 }
250
251 bool Shaft::AddFloor(Wall *wall, int floor, const std::string &name, const std::string &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)
252 {
253         //exit with an error if floor is invalid
254         if (IsValidFloor(floor) == false)
255                 return ReportError("AddFloor: Floor " + ToString(floor) + " out of range");
256
257         //get shaft extents
258         float altitude = sbs->GetFloor(floor)->Altitude;
259
260         //recalculate shaft extents if needed
261         if (altitude + voffset1 < bottom)
262                 bottom = altitude + voffset1;
263         if (altitude + voffset2 < bottom)
264                 bottom = altitude + voffset2;
265         if (altitude + voffset1 > top)
266                 top = altitude + voffset1;
267         if (altitude + voffset2 > top)
268                 top = altitude + voffset2;
269
270         return sbs->AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, voffset1, voffset2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
271 }
272
273 void Shaft::Enabled(int floor, bool value, bool EnableShaftDoors)
274 {
275         SBS_PROFILE("Shaft::Enabled");
276         if (IsEnabledFloor(floor) != value && floor >= startfloor && floor <= endfloor && EnableCheck == false)
277         {
278                 //turns shaft on/off for a specific floor
279
280                 GetMeshObject(floor)->Enabled(value);
281                 EnableArray[floor - startfloor] = value;
282
283                 //doors
284                 for (size_t i = 0; i < DoorArray[floor - startfloor].size(); i++)
285                 {
286                         if (DoorArray[floor - startfloor][i])
287                                 DoorArray[floor - startfloor][i]->Enabled(value);
288                 }
289
290                 //controls
291                 for (size_t i = 0; i < ControlArray[floor - startfloor].size(); i++)
292                 {
293                         if (ControlArray[floor - startfloor][i])
294                                 ControlArray[floor - startfloor][i]->Enabled(value);
295                 }
296
297                 //triggers
298                 /*for (size_t i = 0; i < TriggerArray[floor - startfloor].size(); i++)
299                 {
300                         if (TriggerArray[floor - startfloor][i])
301                                 TriggerArray[floor - startfloor][i]->Enabled(value);
302                 }*/
303
304                 //models
305                 for (size_t i = 0; i < ModelArray[floor - startfloor].size(); i++)
306                 {
307                         if (ModelArray[floor - startfloor][i])
308                                 ModelArray[floor - startfloor][i]->Enabled(value);
309                 }
310
311                 if (EnableShaftDoors == true)
312                 {
313                         for (size_t i = 0; i < elevators.size(); i++)
314                         {
315                                 Elevator *elevator = sbs->GetElevator(elevators[i]);
316                                 if (elevator)
317                                 {
318                                         for (size_t j = 1; j <= elevator->GetCarCount(); j++)
319                                         {
320                                                 ElevatorCar *car = elevator->GetCar((int)j);
321
322                                                 for (size_t k = 0; k < car->ServicedFloors.size(); k++)
323                                                 {
324                                                         if (car->ServicedFloors[k] == floor)
325                                                                 car->ShaftDoorsEnabled(0, car->ServicedFloors[k], value);
326                                                 }
327                                         }
328                                 }
329                         }
330                 }
331         }
332 }
333
334 void Shaft::EnableWholeShaft(bool value, bool EnableShaftDoors, bool force)
335 {
336         //turn on/off entire shaft
337
338         if (value == false && ShowFullShaft == true)
339                 return;
340
341         if (force == true)
342                 IsEnabled = !value;
343
344         if (IsEnabled == !value && EnableCheck == false)
345         {
346                 for (int i = startfloor; i <= endfloor; i++)
347                 {
348                         if (force == true)
349                                 EnableArray[i - startfloor] = !value;
350                         Enabled(i, value, EnableShaftDoors);
351                 }
352         }
353
354         //enable/disable dynamic meshes
355         dynamic_mesh->Enabled(value);
356         ShaftDoorContainer->Enabled(value);
357         DoorWrapper->Enabled(value);
358
359         IsEnabled = value;
360         if (ShowFullShaft == true)
361                 EnableCheck = true;
362 }
363
364 bool Shaft::IsInShaft(const Ogre::Vector3 &position)
365 {
366         //SBS_PROFILE("Shaft::IsInShaft");
367
368         //if last position is the same as new, return previous result
369         if (position.positionEquals(lastposition) == true && checkfirstrun == false)
370                 return lastcheckresult;
371
372         checkfirstrun = false;
373
374         if (position.y > bottom && position.y < top && ShaftArray.size() > 0)
375         {
376                 //first determine if camera has X and Z values within the first shaft floor's bounding box
377                 if (ShaftArray[0]->InBoundingBox(position, false) == true)
378                 {
379                         //do a hit beam test from the position to the bottom of the shaft, to see if it hits a shaft floor
380                         bool result = (ShaftArray[0]->HitBeam(position, Ogre::Vector3::NEGATIVE_UNIT_Y, position.y - (bottom - 1)) >= 0);
381
382                         //cache values
383                         lastcheckresult = result;
384                         lastposition = position;
385
386                         return result;
387                 }
388         }
389
390         //cache values
391         lastcheckresult = false;
392         lastposition = position;
393
394         return false;
395 }
396
397 void Shaft::CutFloors(bool relative, const Ogre::Vector2 &start, const Ogre::Vector2 &end, float startvoffset, float endvoffset)
398 {
399         //Cut through floor/ceiling polygons on all associated levels, within the voffsets
400
401         Report("cutting...");
402
403         float voffset1, voffset2;
404         cutstart = start;
405         cutend = end;
406
407         if (!sbs->GetFloor(startfloor) || !sbs->GetFloor(endfloor))
408                 return;
409
410         for (int i = startfloor; i <= endfloor; i++)
411         {
412                 Floor *floorptr = sbs->GetFloor(i);
413                 if (!floorptr)
414                         continue;
415
416                 voffset1 = 0;
417                 voffset2 = floorptr->FullHeight() + 1;
418
419                 if (i == startfloor)
420                         voffset1 = startvoffset;
421                 else if (i == endfloor)
422                         voffset2 = endvoffset;
423
424                 if (relative == true)
425                         floorptr->Cut(Ogre::Vector3(GetPosition().x + start.x, voffset1, GetPosition().z + start.y), Ogre::Vector3(GetPosition().x + end.x, voffset2, GetPosition().z + end.y), false, true, false);
426                 else
427                         floorptr->Cut(Ogre::Vector3(start.x, voffset1, start.y), Ogre::Vector3(end.x, voffset2, end.y), false, true, false);
428                 floorptr = 0;
429         }
430
431         //cut external
432         voffset1 = sbs->GetFloor(startfloor)->Altitude + startvoffset;
433         voffset2 = sbs->GetFloor(endfloor)->Altitude + endvoffset;
434
435         for (size_t i = 0; i < sbs->External->Walls.size(); i++)
436         {
437                 if (relative == true)
438                         sbs->Cut(sbs->External->Walls[i], Ogre::Vector3(GetPosition().x + start.x, voffset1, GetPosition().z + start.y), Ogre::Vector3(GetPosition().x + end.x, voffset2, GetPosition().z + end.y), false, true);
439                 else
440                         sbs->Cut(sbs->External->Walls[i], Ogre::Vector3(start.x, voffset1, start.y), Ogre::Vector3(end.x, voffset2, end.y), false, true);
441         }
442 }
443
444 bool Shaft::Cut(bool relative, int floor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, bool cutwalls, bool cutfloors, int checkwallnumber)
445 {
446         //Cut through a wall segment
447         //the Y values in start and end are both relative to the floor's altitude
448
449         //exit with an error if floor is invalid
450         if (IsValidFloor(floor) == false)
451         {
452                 if (sbs->Verbose)
453                         ReportError("Cut: Floor " + ToString(floor) + " out of range");
454                 else
455                         sbs->LastError = "Cut: Floor " + ToString(floor) + " out of range";
456                 return false;
457         }
458
459         if (!sbs->GetFloor(floor))
460                 return false;
461
462         for (size_t i = 0; i < GetMeshObject(floor)->Walls.size(); i++)
463         {
464                 bool reset = true;
465                 if (i > 0)
466                         reset = false;
467
468                 if (relative == true)
469                         sbs->Cut(GetMeshObject(floor)->Walls[i], Ogre::Vector3(start.x, start.y, start.z), Ogre::Vector3(end.x, end.y, end.z), cutwalls, cutfloors, checkwallnumber, reset);
470                 else
471                         sbs->Cut(GetMeshObject(floor)->Walls[i], Ogre::Vector3(start.x - GetPosition().x, start.y, start.z - GetPosition().z), Ogre::Vector3(end.x - GetPosition().x, end.y, end.z - GetPosition().z), cutwalls, cutfloors, checkwallnumber, reset);
472         }
473         return true;
474 }
475
476 void Shaft::EnableRange(int floor, int range, bool value, bool EnableShaftDoors)
477 {
478         //turn on/off a range of floors
479         //if range is 3, show shaft on current floor (floor), and 1 floor below and above (3 total floors)
480         //if range is 1, show only the current floor (floor)
481
482         //exit if ShowFullShaft is true
483         if (ShowFullShaft == true)
484                 return;
485
486         if (!sbs->GetFloor(floor))
487                 return;
488
489         SBS_PROFILE("Shaft::EnableRange");
490
491         //range must be greater than 0
492         if (range < 1)
493                 range = 1;
494
495         //range must be an odd number; if it's even, then add 1
496         if (IsEven(range) == true)
497                 range++;
498
499         int additionalfloors;
500         if (range > 1)
501                 additionalfloors = (range - 1) / 2;
502         else
503                 additionalfloors = 0;
504
505         //disable floors 1 floor outside of range
506         if (value == true)
507         {
508                 if (floor - additionalfloors - 1 >= startfloor && floor - additionalfloors - 1 <= endfloor)
509                 {
510                         if (sbs->GetFloor(floor)->IsInGroup(floor - additionalfloors - 1) == false) //only disable if not in group
511                                 Enabled(floor - additionalfloors - 1, false, EnableShaftDoors);
512                 }
513                 if (floor + additionalfloors + 1 >= startfloor && floor + additionalfloors + 1 <= endfloor)
514                 {
515                         if (sbs->GetFloor(floor)->IsInGroup(floor + additionalfloors + 1) == false) //only disable if not in group
516                                 Enabled(floor + additionalfloors + 1, false, EnableShaftDoors);
517                 }
518         }
519
520         //enable floors within range
521         for (int i = floor - additionalfloors; i <= floor + additionalfloors; i++)
522         {
523                 if (i >= startfloor && i <= endfloor)
524                         Enabled(i, value, EnableShaftDoors);
525         }
526 }
527
528 bool Shaft::IsEnabledFloor(int floor)
529 {
530         if (floor >= startfloor && floor <= endfloor)
531                 return EnableArray[floor - startfloor];
532         else
533                 return false;
534 }
535
536 void Shaft::AddShowFloor(int floor)
537 {
538         //adds a floor number to the ShowFloors list
539
540         if (IsShowFloor(floor))
541                 return;
542
543         ShowFloorsList.push_back(floor);
544         std::sort(ShowFloorsList.begin(), ShowFloorsList.end());
545 }
546
547 void Shaft::RemoveShowFloor(int floor)
548 {
549         //removes a floor number from the ShowFloors list
550
551         for (size_t i = 0; i < ShowFloorsList.size(); i++)
552         {
553                 if (ShowFloorsList[i] == floor)
554                 {
555                         ShowFloorsList.erase(ShowFloorsList.begin() + i);
556                         return;
557                 }
558         }
559 }
560
561 bool Shaft::IsShowFloor(int floor)
562 {
563         //return true if a floor is in the ShowFloors list
564
565         for (size_t i = 0; i < ShowFloorsList.size(); i++)
566         {
567                 if (ShowFloorsList[i] == floor)
568                         return true;
569         }
570         return false;
571 }
572
573 void Shaft::AddShowOutside(int floor)
574 {
575         //adds a floor number to the ShowOutside list
576
577         if (IsShowOutside(floor))
578                 return;
579
580         ShowOutsideList.push_back(floor);
581         std::sort(ShowOutsideList.begin(), ShowOutsideList.end());
582 }
583
584 void Shaft::RemoveShowOutside(int floor)
585 {
586         //removes a floor number from the ShowOutside list
587
588         for (size_t i = 0; i < ShowOutsideList.size(); i++)
589         {
590                 if (ShowOutsideList[i] == floor)
591                 {
592                         ShowOutsideList.erase(ShowOutsideList.begin() + i);
593                         return;
594                 }
595         }
596 }
597
598 bool Shaft::IsShowOutside(int floor)
599 {
600         //return true if a floor is in the ShowOutside list
601
602         for (size_t i = 0; i < ShowOutsideList.size(); i++)
603         {
604                 if (ShowOutsideList[i] == floor)
605                         return true;
606         }
607         return false;
608 }
609
610 void Shaft::AddShowInterfloor(int floor)
611 {
612         //adds a floor number to the ShowInterfloors list
613
614         if (IsShowInterfloor(floor))
615                 return;
616
617         ShowInterfloorsList.push_back(floor);
618         std::sort(ShowInterfloorsList.begin(), ShowInterfloorsList.end());
619 }
620
621 void Shaft::RemoveShowInterfloor(int floor)
622 {
623         //removes a floor number from the ShowInterfloors list
624
625         for (size_t i = 0; i < ShowInterfloorsList.size(); i++)
626         {
627                 if (ShowInterfloorsList[i] == floor)
628                 {
629                         ShowInterfloorsList.erase(ShowInterfloorsList.begin() + i);
630                         return;
631                 }
632         }
633 }
634
635 bool Shaft::IsShowInterfloor(int floor)
636 {
637         //return true if a floor is in the ShowInterfloors list
638
639         for (size_t i = 0; i < ShowInterfloorsList.size(); i++)
640         {
641                 if (ShowInterfloorsList[i] == floor)
642                         return true;
643         }
644         return false;
645 }
646
647 bool Shaft::IsValidFloor(int floor)
648 {
649         //return true if the shaft services the specified floor
650
651         if (floor < startfloor || floor > endfloor)
652                 return false;
653
654         if (!ShaftArray[floor - startfloor])
655                 return false;
656
657         return true;
658 }
659
660 void Shaft::AddElevator(int number)
661 {
662         //add specified elevator to list
663
664         for (size_t i = 0; i < elevators.size(); i++)
665         {
666                 if (elevators[i] == number)
667                         return;
668         }
669
670         elevators.push_back(number);
671         std::sort(elevators.begin(), elevators.end());
672 }
673
674 void Shaft::RemoveElevator(int number)
675 {
676         //remove specified elevator from list
677         for (size_t i = 0; i < elevators.size(); i++)
678         {
679                 if (elevators[i] == number)
680                 {
681                         elevators.erase(elevators.begin() + i);
682                         return;
683                 }
684         }
685 }
686
687 void Shaft::RemoveLight(Light *light)
688 {
689         //remove a light reference (does not delete the object itself)
690         for (size_t i = 0; i < lights.size(); i++)
691         {
692                 for (size_t j = 0; j < lights[i].size(); j++)
693                 {
694                         if (lights[i][j] == light)
695                         {
696                                 lights[i].erase(lights[i].begin() + j);
697                                 return;
698                         }
699                 }
700         }
701 }
702
703 void Shaft::RemoveModel(Model *model)
704 {
705         //remove a model reference (does not delete the object itself)
706         for (size_t i = 0; i < ModelArray.size(); i++)
707         {
708                 for (size_t j = 0; j < ModelArray[i].size(); j++)
709                 {
710                         if (ModelArray[i][j] == model)
711                         {
712                                 ModelArray[i].erase(ModelArray[i].begin() + j);
713                                 return;
714                         }
715                 }
716         }
717 }
718
719 void Shaft::RemoveControl(Control *control)
720 {
721         //remove a control reference (does not delete the object itself)
722         for (size_t i = 0; i < ControlArray.size(); i++)
723         {
724                 for (size_t j = 0; j < ControlArray[i].size(); j++)
725                 {
726                         if (ControlArray[i][j] == control)
727                         {
728                                 ControlArray[i].erase(ControlArray[i].begin() + j);
729                                 return;
730                         }
731                 }
732         }
733 }
734
735 void Shaft::RemoveTrigger(Trigger *trigger)
736 {
737         //remove a trigger reference (does not delete the object itself)
738         /*for (size_t i = 0; i < TriggerArray.size(); i++)
739         {
740                 for (size_t j = 0; j < TriggerArray[i].size(); j++)
741                 {
742                         if (TriggerArray[i][j] == trigger)
743                         {
744                                 TriggerArray[i].erase(TriggerArray[i].begin() + j);
745                                 return;
746                         }
747                 }
748         }*/
749 }
750
751 MeshObject* Shaft::GetMeshObject(int floor)
752 {
753         //returns the mesh object for the specified floor
754
755         if (!IsValidFloor(floor))
756                 return 0;
757
758         return ShaftArray[floor - startfloor];
759 }
760
761 void Shaft::Report(const std::string &message)
762 {
763         //general reporting function
764         sbs->Report("Shaft " + ToString(ShaftNumber) + ": " + message);
765 }
766
767 bool Shaft::ReportError(const std::string &message)
768 {
769         //general reporting function
770         return sbs->ReportError("Shaft " + ToString(ShaftNumber) + ": " + message);
771 }
772
773 Light* Shaft::AddLight(int floor, const std::string &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)
774 {
775         //add a global light
776
777         //exit if floor is invalid
778         if (!IsValidFloor(floor))
779                 return 0;
780
781         Light* light = new Light(GetMeshObject(floor), 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);
782         lights[floor - startfloor].push_back(light);
783         return light;
784 }
785
786 Model* Shaft::AddModel(int floor, const std::string &name, const std::string &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)
787 {
788         //add a model
789
790         //exit if floor is invalid
791         if (!IsValidFloor(floor))
792                 return 0;
793
794         Model* model = new Model(GetMeshObject(floor), name, filename, center, position, rotation, max_render_distance, scale_multiplier, enable_physics, restitution, friction, mass);
795         if (model->load_error == true)
796         {
797                 delete model;
798                 return 0;
799         }
800         ModelArray[floor - startfloor].push_back(model);
801         return model;
802 }
803
804 void Shaft::AddModel(int floor, Model *model)
805 {
806         //add a model reference
807
808         if (!model)
809                 return;
810
811         //exit if floor is invalid
812         if (!IsValidFloor(floor))
813                 return;
814
815         for (size_t i = 0; i < ModelArray[floor - startfloor].size(); i++)
816         {
817                 if (ModelArray[floor - startfloor][i] == model)
818                         return;
819         }
820
821         ModelArray[floor - startfloor].push_back(model);
822 }
823
824 Control* Shaft::AddControl(int floor, 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)
825 {
826         //add a control
827
828         //exit if floor is invalid
829         if (!IsValidFloor(floor))
830                 return 0;
831
832         std::vector<Action*> actionnull; //not used
833         Control* control = new Control(GetMeshObject(floor), name, false, sound, action_names, actionnull, textures, direction, width, height, true, selection_position);
834         control->Move(CenterX, voffset, CenterZ);
835         ControlArray[floor - startfloor].push_back(control);
836         return control;
837 }
838
839 Trigger* Shaft::AddTrigger(int floor, const std::string &name, const std::string &sound_file, Ogre::Vector3 &area_min, Ogre::Vector3 &area_max, std::vector<std::string> &action_names)
840 {
841         //triggers disabled for now
842
843         //add a trigger
844
845         //exit if floor is invalid
846         /*if (!IsValidFloor(floor))
847                 return 0;
848
849         Trigger* trigger = new Trigger(GetMeshObject(floor), name, false, sound_file, area_min, area_max, action_names);
850         TriggerArray[floor - startfloor].push_back(trigger);
851         return trigger;*/
852         return 0;
853 }
854
855 void Shaft::ReplaceTexture(const std::string &oldtexture, const std::string &newtexture)
856 {
857         for (int i = startfloor; i <= endfloor; i++)
858                 GetMeshObject(i)->ReplaceTexture(oldtexture, newtexture);
859 }
860
861 void Shaft::OnInit()
862 {
863         //startup initialization of shafts
864
865         if (ShowFullShaft == false)
866                 EnableWholeShaft(false, true);
867         else
868                 EnableWholeShaft(true, true, true);
869 }
870
871 Door* Shaft::AddDoor(int floor, const std::string &open_sound, const std::string &close_sound, bool open_state, const std::string &texture, float thickness, int direction, float speed, float CenterX, float CenterZ, float width, float height, float voffset, float tw, float th)
872 {
873         //add a door
874
875         //exit with an error if floor is invalid
876         if (IsValidFloor(floor) == false)
877         {
878                 ReportError("AddDoor: Floor " + ToString(floor) + " out of range");
879                 return 0;
880         }
881
882         Floor *floorptr = sbs->GetFloor(floor);
883         if (!floorptr)
884                 return 0;
885
886         float x1, z1, x2, z2;
887         //set up coordinates
888         if (direction < 5)
889         {
890                 x1 = CenterX;
891                 x2 = CenterX;
892                 z1 = CenterZ - (width / 2);
893                 z2 = CenterZ + (width / 2);
894         }
895         else
896         {
897                 x1 = CenterX - (width / 2);
898                 x2 = CenterX + (width / 2);
899                 z1 = CenterZ;
900                 z2 = CenterZ;
901         }
902
903         //cut area
904         sbs->ResetDoorwayWalls();
905         if (direction < 5)
906         {
907                 Cut(1, floor, Ogre::Vector3(x1 - 0.5f, voffset, z1), Ogre::Vector3(x2 + 0.5f, voffset + height, z2), true, false, 1);
908                 floorptr->Cut(Ogre::Vector3(GetPosition().x + x1 - 0.5f, floorptr->GetBase(true) + voffset, GetPosition().z + z1), Ogre::Vector3(GetPosition().x + x2 + 0.5f, floorptr->GetBase(true) + voffset + height, GetPosition().z + z2), true, false, true, 2);
909         }
910         else
911         {
912                 Cut(1, floor, Ogre::Vector3(x1, voffset, z1 - 0.5f), Ogre::Vector3(x2, voffset + height, z2 + 0.5f), true, false, 1);
913                 floorptr->Cut(Ogre::Vector3(GetPosition().x + x1, floorptr->GetBase(true) + voffset, GetPosition().z + z1 - 0.5f), Ogre::Vector3(GetPosition().x + x2, floorptr->GetBase(true) + voffset + height, GetPosition().z + z2 + 0.5f), true, false, true, 2);
914         }
915
916         //create doorway walls
917         sbs->AddDoorwayWalls(GetMeshObject(floor), "Connection Walls", "ConnectionWall", 0, 0);
918
919         int index = floor - startfloor;
920         std::string num = ToString((int)DoorArray[index].size());
921         std::string name = "Shaft " + ToString(ShaftNumber) + ":Door " + ToString(floor) + ":" + num;
922
923         Door* door = new Door(GetMeshObject(floor), DoorWrapper, name, open_sound, close_sound, open_state, texture, thickness, direction, speed, CenterX, CenterZ, width, height, floorptr->GetBase(true) + voffset, tw, th);
924         DoorArray[index].push_back(door);
925
926         floorptr = 0;
927         return door;
928 }
929
930 void Shaft::RemoveDoor(Door *door)
931 {
932         //remove a door reference (this does not delete the object)
933         for (size_t i = 0; i < DoorArray.size(); i++)
934         {
935                 for (size_t j = 0; j < DoorArray[i].size(); j++)
936                 {
937                         if (DoorArray[i][j] == door)
938                         {
939                                 DoorArray[i].erase(DoorArray[i].begin() + j);
940                                 return;
941                         }
942                 }
943         }
944 }
945
946 void Shaft::Check(Ogre::Vector3 position, int current_floor)
947 {
948         Elevator *elevator = sbs->GetElevator(sbs->ElevatorNumber);
949
950         if (!elevator)
951                 return;
952
953         ElevatorCar *car = elevator->GetCar(sbs->CarNumber);
954
955         if (!car)
956                 return;
957
958         SBS_PROFILE("Shaft::Check");
959
960         if (IsInShaft(position) == true)
961         {
962                 if (InsideShaft == false && sbs->InElevator == false)
963                 {
964                         //user is in the shaft
965                         InsideShaft = true;
966                         sbs->InShaft = true;
967                         InElevator = false;
968
969                         //turn on entire shaft
970                         EnableWholeShaft(true, true);
971                 }
972                 else if (InsideShaft == true && sbs->InElevator == true)
973                 {
974                         //user has moved from the shaft to an elevator
975                         InsideShaft = false;
976                         sbs->InShaft = false;
977                         InElevator = true;
978
979                         EnableWholeShaft(ShowFullShaft, true);
980                 }
981                 else if (InsideShaft == false && sbs->InElevator == true && ShowFullShaft == false)
982                 {
983                         //if user is in an elevator, show a range of the shaft at a time (while it's moving)
984                         EnableRange(current_floor, sbs->ShaftDisplayRange, true, false);
985                         car->ShaftDoorsEnabledRange(0, current_floor, sbs->ShaftDisplayRange);
986                 }
987
988                 //turn on related floors if ShowFloors is true
989                 //display a selected range of floors in the floor list if the user is in a moving elevator
990                 if (InsideShaft == false && sbs->InElevator == true && elevator->IsMoving == true && elevator->Leveling == false)
991                 {
992                         if (ShowFloors == 1)
993                                 sbs->EnableFloorRange(current_floor, sbs->FloorDisplayRange, true, true, ShaftNumber);
994
995                         if (ShowOutside == true)
996                         {
997                                 if (IsShowOutside(current_floor) == true)
998                                 {
999                                         sbs->EnableSkybox(true);
1000                                         sbs->EnableBuildings(true);
1001                                         sbs->EnableLandscape(true);
1002                                         sbs->EnableExternal(true);
1003                                 }
1004                                 else
1005                                 {
1006                                         sbs->EnableSkybox(false);
1007                                         sbs->EnableBuildings(false);
1008                                         sbs->EnableLandscape(false);
1009                                         sbs->EnableExternal(false);
1010                                 }
1011                         }
1012                 }
1013
1014                 //display the full range of floors in the floor list
1015                 if (ShowFloors == 2 && ShowFloorsFull_Enabled == false)
1016                 {
1017                         ShowFloorsFull_Enabled = true;
1018                         for (size_t i = 0; i < ShowFloorsList.size(); i++)
1019                         {
1020                                 Floor *floor = sbs->GetFloor(ShowFloorsList[i]);
1021                                 if (floor->IsEnabled == false)
1022                                 {
1023                                         floor->Enabled(true);
1024                                         //floor->EnableGroup(true);
1025                                 }
1026                         }
1027                 }
1028
1029                 //display interfloors
1030                 if (ShowInterfloors == true)
1031                 {
1032                         for (size_t i = 0; i < ShowInterfloorsList.size(); i++)
1033                         {
1034                                 Floor *floor = sbs->GetFloor(ShowInterfloorsList[i]);
1035                                 if (floor->IsInterfloorEnabled == false)
1036                                         floor->EnableInterfloor(true);
1037                         }
1038                 }
1039
1040         }
1041         else if (InsideShaft == true || InElevator == true)
1042         {
1043                 //user has moved out of the shaft
1044                 InsideShaft = false;
1045                 sbs->InShaft = false;
1046                 InElevator = false;
1047
1048                 //turn off shaft
1049                 EnableWholeShaft(false, true, true);
1050
1051                 //disable floors listed in ShowFloors list, when "full" mode is enabled
1052                 if (ShowFloors == 2 && ShowFloorsFull_Enabled == true)
1053                 {
1054                         ShowFloorsFull_Enabled = false;
1055                         for (size_t i = 0; i < ShowFloorsList.size(); i++)
1056                         {
1057                                 Floor *floor = sbs->GetFloor(ShowFloorsList[i]);
1058                                 if (floor->IsEnabled == true && sbs->camera->CurrentFloor != floor->Number)
1059                                 {
1060                                         //don't disable floors that were originally enabled as part of the camera floor's group
1061                                         if ((floor->EnabledGroup == true && floor->EnabledGroup_Floor == sbs->camera->CurrentFloor) == false)
1062                                         {
1063                                                 //only disable floor if not part of the camera floor's group
1064                                                 if (floor->IsInGroup(sbs->camera->CurrentFloor) == false)
1065                                                 {
1066                                                         floor->Enabled(false);
1067                                                         //floor->EnableGroup(false);
1068                                                 }
1069                                         }
1070                                 }
1071                         }
1072                 }
1073
1074                 //disable interfloors
1075                 if (ShowInterfloors == true)
1076                 {
1077                         for (size_t i = 0; i < ShowInterfloorsList.size(); i++)
1078                         {
1079                                 Floor *floor = sbs->GetFloor(ShowInterfloorsList[i]);
1080                                 if (floor->IsInterfloorEnabled == true && floor->IsEnabled == false)
1081                                         floor->EnableInterfloor(false);
1082                         }
1083                 }
1084         }
1085         else if (InsideShaft == false)
1086         {
1087                 //show specified shaft range if outside the shaft
1088                 EnableRange(current_floor, sbs->ShaftOutsideDisplayRange, true, true);
1089         }
1090 }
1091
1092 void Shaft::Loop()
1093 {
1094         //shaft runloop
1095
1096         SBS_PROFILE("Shaft::Loop");
1097
1098         LoopChildren();
1099 }
1100
1101 Model* Shaft::GetModel(int floor, std::string name)
1102 {
1103         //get a model by name
1104
1105         //exit if floor is invalid
1106         if (!IsValidFloor(floor))
1107                 return 0;
1108
1109         SetCase(name, false);
1110
1111         int index = floor - startfloor;
1112
1113         for (size_t i = 0; i < ModelArray[index].size(); i++)
1114         {
1115                 if (SetCaseCopy(ModelArray[index][i]->GetName(), false) == name)
1116                         return ModelArray[index][i];
1117         }
1118
1119         return 0;
1120 }
1121
1122 void Shaft::SetShowFull(bool value)
1123 {
1124         ShowFullShaft = value;
1125
1126         //force the combining of dynamic meshes, since they'll be fully shown
1127         dynamic_mesh->force_combine = value;
1128         DoorWrapper->force_combine = value;
1129         ShaftDoorContainer->force_combine = value;
1130 }
1131
1132 }