1 /*-- Switch --*/
2
3 #include Library_Switch
4
5 local handle, last_controlling_clonk;
6
Initialize()7 public func Initialize()
8 {
9 handle = CreateObject(Switch_Handle);
10 if (handle) handle->SetSwitch(this);
11 SetAction("Idle");
12 }
13
SaveScenarioObject(props)14 public func SaveScenarioObject(props)
15 {
16 if (!inherited(props, ...)) return false;
17 if (handle)
18 {
19 var pos = GetHandlePosition();
20 if (pos) props->AddCall("Handle", this, "SetSwitchDir", (pos>0)-(pos<0));
21 }
22 if (left_action || right_action) props->AddCall("Action", this, "SetActions", left_action, right_action);
23 return true;
24 }
25
SetActions(new_left_action,new_right_action)26 public func SetActions(new_left_action, new_right_action)
27 {
28 left_action = new_left_action;
29 right_action = new_right_action;
30 return true;
31 }
32
ControlUp(object clonk)33 public func ControlUp(object clonk)
34 {
35 var dir = Rot2Dir(0,-1);
36 if (!dir) return false;
37 return ControlSwitchDir(clonk, dir);
38 }
39
ControlDown(object clonk)40 public func ControlDown(object clonk)
41 {
42 var dir = Rot2Dir(0,+1);
43 if (!dir) return false;
44 return ControlSwitchDir(clonk, dir);
45 }
46
ControlLeft(object clonk)47 public func ControlLeft(object clonk)
48 {
49 var dir = Rot2Dir(-1,0);
50 if (!dir) return false;
51 return ControlSwitchDir(clonk, dir);
52 }
53
ControlRight(object clonk)54 public func ControlRight(object clonk)
55 {
56 var dir = Rot2Dir(+1,0);
57 if (!dir) return false;
58 return ControlSwitchDir(clonk, dir);
59 }
60
ControlSwitchDir(object clonk,int dir)61 private func ControlSwitchDir(object clonk, int dir)
62 {
63 if (!handle || (!GetSwitchTarget() && !right_action && !left_action))
64 {
65 Sound("Structures::SwitchStuck");
66 Message("$MsgStuck$");
67 return false;
68 }
69 // remember clonk for clalbacks
70 last_controlling_clonk = clonk;
71 // move handle
72 var handle_pos = GetHandlePosition();
73 if (dir<0)
74 {
75 if (GetAction() == "SwitchLeft") return false;
76 if (handle_pos == -MaxHandleAngle) { Sound("Structures::SwitchStuck"); return false; }
77 SetAction("SwitchLeft");
78 }
79 else
80 {
81 if (GetAction() == "SwitchRight") return false;
82 if (handle_pos == MaxHandleAngle) { Sound("Structures::SwitchStuck"); return false; }
83 SetAction("SwitchRight");
84 }
85 Sound("Structures::SwitchMove");
86 return true;
87 }
88
Rot2Dir(int dx,int dy)89 private func Rot2Dir(int dx, int dy)
90 {
91 // Convert direction dx,dy in world coordinates to horizontal direction in local coordinates
92 var r = GetR();
93 return BoundBy(dx*Cos(r, 3) + dy*Sin(r, 3), -1,+1);
94 }
95
GetHandlePosition()96 private func GetHandlePosition()
97 {
98 // returns position of handle relative to switch in degrees [-180 to +180]
99 return (handle->GetR() - GetR() + 540) % 360 - 180;
100 }
101
SetSwitchDir(int to_dir)102 public func SetSwitchDir(int to_dir)
103 {
104 // Set angle of switch without doing any effects or callbacks
105 if (!handle) return false;
106 return handle->SetR(GetR() + MaxHandleAngle * to_dir);
107 }
108
SetR(int to_r)109 public func SetR(int to_r)
110 {
111 // Set rotation: Also update handle rotation
112 if (handle) handle->SetR(handle->GetR() + to_r - GetR());
113 return _inherited(to_r, ...);
114 }
115
SwitchingTimer(int dir)116 private func SwitchingTimer(int dir)
117 {
118 if (!handle || (!GetSwitchTarget() && !right_action && !left_action))
119 {
120 Sound("Structures::SwitchStuck");
121 return SetAction("Idle");
122 }
123 var handle_pos = GetHandlePosition();
124 var handle_pos_new = BoundBy(handle_pos + HandleSpeed * dir, -MaxHandleAngle, +MaxHandleAngle);
125 if (!handle_pos_new) handle_pos_new = dir; // avoid direct central position, so player cannot force the same direction twice
126 handle->SetR(GetR() + handle_pos_new);
127 // Reached end?
128 if (handle_pos_new == MaxHandleAngle * dir) SetAction("Idle");
129 // Passed by middle? (last call because callback might delete switch)
130 if (handle_pos * handle_pos_new <= 0)
131 {
132 Sound("Structures::SwitchFlip*");
133 DoSwitchFlip(last_controlling_clonk, dir);
134 }
135 return true;
136 }
137
DoSwitchFlip(object clonk,int dir)138 private func DoSwitchFlip(object clonk, int dir)
139 {
140 // Perform action associated to this switch
141 if (dir > 0)
142 {
143 // Open/close should be aligned to vertical component of direction
144 SetSwitchState(GetR() < 0, clonk); // switch on if rotation < 0
145 // Action last; it may delete the door/clonk/etc.
146 if (right_action)
147 UserAction->EvaluateAction(right_action, this, clonk);
148 }
149 else
150 {
151 // Open/close should be aligned to vertical component of direction
152 SetSwitchState(GetR() >= 0, clonk); // switch off if rotation < 0
153 // Action last; it may delete the door/clonk/etc.
154 if (left_action)
155 UserAction->EvaluateAction(left_action, this, clonk);
156 }
157 return false;
158 }
159
SwitchingLeft()160 private func SwitchingLeft() { return SwitchingTimer(-1); }
SwitchingRight()161 private func SwitchingRight() { return SwitchingTimer(+1); }
162
163 local ActMap = {
164 SwitchLeft = {
165 Prototype = Action,
166 Name = "SwitchLeft",
167 Procedure = DFA_NONE,
168 Length = 1,
169 Delay = 1,
170 NextAction = "SwitchLeft",
171 StartCall = "SwitchingLeft",
172 FacetBase = 1,
173 },
174 SwitchRight = {
175 Prototype = Action,
176 Name = "SwitchRight",
177 Procedure = DFA_NONE,
178 Length = 1,
179 Delay = 1,
180 NextAction = "SwitchRight",
181 StartCall = "SwitchingRight",
182 FacetBase = 1,
183 },
184 };
185
186 local Name = "$Name$";
187 local Description = "$Description$";
188 local Touchable = 2;
189 local Plane = 270;
190 local MaxHandleAngle = 45;
191 local HandleSpeed = 6;
192 local Components = { Rock = 3, Metal=1 };
193 local left_action, right_action; // Custom editor-selected actions on switch handling
194
195 local EditorActions = {
196 };
197
Definition(def)198 func Definition(def)
199 {
200 // Graphics
201 SetProperty("PictureTransformation", Trans_Mul(Trans_Scale(800), Trans_Translate(0,0,0),Trans_Rotate(-20,1,0,0),Trans_Rotate(-30,0,1,0)), def);
202 SetProperty("MeshTransformation", Trans_Rotate(-13,0,1,0), def);
203 // Editor properties
204 if (!def.EditorProps) def.EditorProps = {};
205 def.EditorProps.left_action = new UserAction.Prop { Name="$LeftAction$" };
206 def.EditorProps.right_action = new UserAction.Prop { Name="$RightAction$" };
207 // Actions
208 if (!def.EditorActions) def.EditorActions = {};
209 def.EditorActions.SwitchLeft = { Name = "$SwitchLeft$", Command = "ControlSwitchDir(nil, -1)" };
210 def.EditorActions.SwitchRight = { Name = "$SwitchRight$", Command = "ControlSwitchDir(nil, +1)" };
211 def.EditorActions.Rotate = { Name = "$Rotate$", Command = "SetR((GetR()+135)/90*90)" };
212 return _inherited(def, ...);
213 }
214