OSDN Git Service

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