1 /*-- Elevator --*/
2
3 #include Library_Structure
4 #include Library_Ownable
5
6 // used in the elevator case
7 static const Elevator_needed_power = 20;
8
9 local case, rope;
10 local partner, slave;
11
12 /* Editing helpers */
13
14 // Frees a rectangle for the case
CreateShaft(int length)15 public func CreateShaft(int length)
16 {
17 // Move the case out of the way
18 case->SetPosition(case->GetX(), GetY()-10);
19 ClearFreeRect(GetX() + 7 - 38*GetDir(), GetY() + 20, 24, length + 13);
20 // Move the case back
21 case->SetPosition(case->GetX(), GetY()+20);
22 }
23
24 // Move case to specified absolute y position
SetCasePosition(int y)25 public func SetCasePosition(int y)
26 {
27 if (case) return case->SetPosition(case->GetX(), y);
28 return false;
29 }
30
31 // Overloaded to reposition the case
SetDir(new_dir,...)32 public func SetDir(new_dir, ...)
33 {
34 var r = inherited(new_dir, ...);
35 // Update position of child objects on direction change
36 if (case) case->SetPosition(GetX() -19 * GetCalcDir(), case->GetY());
37 if (rope) rope->SetPosition(GetX() -19 * GetCalcDir(), rope->GetY());
38
39 // Set mesh transformation so that the rope on the mesh fits the rope from the elevator case.
40 if (new_dir == DIR_Left)
41 {
42 this.MeshTransformation = Trans_Rotate(-44,0,1,0);
43 }
44 else
45 {
46 this.MeshTransformation = Trans_Rotate(-47,0,1,0);
47 }
48 return r;
49 }
50
51 // Forward config to case
SetNoPowerNeed(bool to_val)52 public func SetNoPowerNeed(bool to_val)
53 {
54 if (case) return case->SetNoPowerNeed(to_val);
55 return false;
56 }
57
EditCursorMoved()58 private func EditCursorMoved()
59 {
60 // Move case and rope along with elevator in editor mode
61 if (case) case->SetPosition(GetX() + GetCaseXOff(), case->GetY());
62 if (rope) rope->SetPosition(GetX() + GetCaseXOff(), GetY() - 13);
63 return true;
64 }
65
66 // return default horizontal offset of case/rope to elevator
GetCaseXOff()67 public func GetCaseXOff() { return -19 * GetCalcDir(); }
68
69 /* Initialization */
70
Construction()71 private func Construction()
72 {
73 // Set default mesh transformation.
74 SetDir(DIR_Left);
75 SetAction("Default");
76 wheel_anim = PlayAnimation("winchSpin", 1, Anim_Const(0), Anim_Const(1000));
77
78 return _inherited(...);
79 }
80
IsHammerBuildable()81 public func IsHammerBuildable() { return true; }
82
Initialize()83 private func Initialize()
84 {
85 SetCategory(C4D_StaticBack);
86 CreateCase();
87 CreateRope();
88
89 if (partner)
90 {
91 if (Inside(partner->GetY(), GetY()-3, GetY()+3))
92 {
93 partner->LetsBecomeFriends(this);
94 SetPosition(GetX(), partner->GetY());
95 }
96 else
97 partner = nil;
98 }
99 return _inherited(...);
100 }
101
CreateCase()102 private func CreateCase()
103 {
104 case = CreateObjectAbove(ElevatorCase, GetCaseXOff(), 33, GetOwner());
105 if (case) case->Connect(this);
106 }
107
GetCase()108 public func GetCase()
109 {
110 return case;
111 }
112
CreateRope()113 private func CreateRope()
114 {
115 rope = CreateObjectAbove(ElevatorRope, GetCaseXOff(), -11, GetOwner());
116 if (rope) rope->SetAction("Be", case.back);
117 }
118
119 /* Destruction */
120
Destruction()121 private func Destruction()
122 {
123 if(rope) rope->RemoveObject();
124 if(case) case->LostElevator();
125 if (partner) partner->LoseCombination();
126 }
127
LostCase()128 public func LostCase()
129 {
130 if(partner) partner->LoseCombination();
131 if(rope) rope->RemoveObject();
132
133 StopEngine();
134
135 // for now: the elevator dies, too
136 Incinerate();
137 }
138
139 /* Effects */
140
141 local wheel_anim, case_speed;
142
StartEngine(int direction,bool silent)143 public func StartEngine(int direction, bool silent)
144 {
145 if (!case) return;
146
147 if (!silent)
148 {
149 Sound("Structures::Elevator::Start", {custom_falloff_distance = 400});
150 ScheduleCall(this, "EngineLoop", 34);
151 }
152 if (wheel_anim == nil) // If for some reason the animation has stopped
153 wheel_anim = PlayAnimation("winchSpin", 1, Anim_Const(0), Anim_Const(1000));
154
155 var begin, end;
156 if (direction == COMD_Up) // Either that or COMD_Down
157 {
158 begin = GetAnimationLength("winchSpin");
159 end = 0;
160 }
161 else
162 {
163 begin = 0;
164 end = GetAnimationLength("winchSpin");
165 }
166
167 case_speed = Abs(case->GetYDir());
168 var speed = 80 - case_speed * 2;
169 SetAnimationPosition(wheel_anim, Anim_Linear(GetAnimationPosition(wheel_anim), begin, end, speed, ANIM_Loop));
170 }
171
EngineLoop()172 public func EngineLoop()
173 {
174 Sound("Structures::Elevator::Moving", {loop_count = 1, custom_falloff_distance = 400});
175 }
176
StopEngine(bool silent)177 public func StopEngine(bool silent)
178 {
179 if (!silent)
180 {
181 Sound("Structures::Elevator::Moving", {loop_count = -1});
182 ClearScheduleCall(this, "EngineLoop");
183 Sound("Structures::Elevator::Stop", {custom_falloff_distance = 400});
184 }
185
186 if (wheel_anim == nil) return;
187
188 case_speed = nil;
189 SetAnimationPosition(wheel_anim, Anim_Const(GetAnimationPosition(wheel_anim)));
190 }
191
192 // Adjusting the turning speed of the wheel to the case's speed
UpdateTurnSpeed()193 private func UpdateTurnSpeed()
194 {
195 if (!case) return;
196 if (case_speed == nil || wheel_anim == nil) return;
197
198 if (Abs(case->GetYDir()) != case_speed)
199 {
200 var begin, end;
201 if (case->GetYDir() < 0) // Either that or COMD_Down
202 {
203 begin = GetAnimationLength("winchSpin");
204 end = 0;
205 }
206 else
207 {
208 begin = 0;
209 end = GetAnimationLength("winchSpin");
210 }
211 case_speed = Abs(case->GetYDir());
212 var speed = 80 - case_speed * 2;
213 SetAnimationPosition(wheel_anim, Anim_Linear(GetAnimationPosition(wheel_anim), begin, end, speed, ANIM_Loop));
214 }
215 }
216
217 /* Construction preview */
218
219 // Definition call by the construction previewer
ConstructionPreview(object previewer,int overlay,int dir)220 public func ConstructionPreview(object previewer, int overlay, int dir)
221 {
222 if (GetType(this) != C4V_Def) return;
223
224 previewer->SetGraphics(nil, Elevator_Case_Front, overlay, GFXOV_MODE_Base);
225 previewer->SetObjDrawTransform(1000, 0, -19000 * (dir*2-1), 0, 1000, 17000, overlay);
226 return true;
227 }
228
229 // Sticking to other elevators
ConstructionCombineWith()230 public func ConstructionCombineWith() { return "CanCombineElevator"; }
ConstructionCombineDirection(object other)231 public func ConstructionCombineDirection(object other)
232 {
233 if (!other) return CONSTRUCTION_STICK_Left | CONSTRUCTION_STICK_Right;
234
235 // Only combine when facing correctly
236 if (other->GetDir() == DIR_Left)
237 return CONSTRUCTION_STICK_Right;
238 return CONSTRUCTION_STICK_Left;
239 }
240
241 // Called to determine if sticking is possible
CanCombineElevator(object previewer)242 public func CanCombineElevator(object previewer)
243 {
244 if (!previewer) return true;
245
246 if (GetDir() == DIR_Left)
247 {
248 if (previewer.direction == DIR_Right && previewer->GetX() > GetX()) return true;
249 }
250 else
251 {
252 if (previewer.direction == DIR_Left && previewer->GetX() < GetX()) return true;
253 }
254 return false;
255 }
256
257 // Called when the elevator construction site is created
CombineWith(object other)258 public func CombineWith(object other)
259 {
260 // Save for use in Initialize
261 partner = other;
262 }
263
264 // Special requirements for the basement of the elevator.
GetBasementWidth()265 public func GetBasementWidth() { return 36; }
GetBasementOffset()266 public func GetBasementOffset() { return [11 * (2 * GetDir() - 1), 0]; }
267
268
269 /* Combination */
270
271 // Called by a new elevator next to this one
272 // The other elevator will be the slave
LetsBecomeFriends(object other)273 public func LetsBecomeFriends(object other)
274 {
275 partner = other;
276 other.slave = true; // Note: This is liberal slavery
277 if (case) case->StartConnection(other.case);
278 }
279
280 // Partner was destroyed or moved
LoseCombination()281 public func LoseCombination()
282 {
283 partner = nil;
284 slave = false;
285 if (case) case->LoseConnection();
286 }
287
288 // Called by our case because the case has a timer anyway
CheckSlavery()289 public func CheckSlavery()
290 {
291 // Check if somehow we moved away from our fellow
292 if (ObjectDistance(partner) > 62 || !Inside(partner->GetY(), GetY()-1, GetY()+1))
293 {
294 LoseCombination();
295 partner->LoseCombination();
296 }
297 }
298
299 /* Scenario saving */
300
SaveScenarioObject(props)301 public func SaveScenarioObject(props)
302 {
303 if (!inherited(props, ...)) return false;
304 props->Remove("Category");
305 if (partner && slave)
306 {
307 props->AddCall("Friends", partner, "LetsBecomeFriends", this);
308 }
309 if (case && case->GetY() > GetY() + 20)
310 {
311 props->AddCall("Shaft", this, "CreateShaft", case->GetY() - GetY() - 20);
312 props->AddCall("Shaft", this, "SetCasePosition", case->GetY());
313 }
314 return true;
315 }
316
317 local ActMap = {
318 Default = {
319 Prototype = Action,
320 Name = "Default",
321 Procedure = DFA_NONE,
322 Directions = 2,
323 FlipDir = 1,
324 Length = 1,
325 Delay = 3,
326 FacetBase = 1,
327 NextAction = "Default",
328 EndCall = "UpdateTurnSpeed",
329 },
330 };
331
Definition(def)332 private func Definition(def) {
333 SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(-20,1,0), Trans_Rotate(-20, 0, 1, 0)));
334 return _inherited(def, ...);
335 }
336 local Name = "$Name$";
337 local Description = "$Description$";
338 local BlastIncinerate = 100;
339 local HitPoints = 70;
340 local Plane = 249;
341 local Components = {Wood = 3, Metal = 1};
342