1
+ --[[
2
+ -- This resource is not finished. Make sure to read the below notes, as well as always use the latest code version from https://github.com/multitheftauto/mtasa-resources/tree/master/%5Bgameplay%5D/parachute2
3
+ -- If you are willing to collaborate finishing this resource, or with testing/feedback
4
+ -- Then please visit the #parachute channel in MTA Development Discord ( invite link: https://discord.gg/GNN6PRtTnu )
5
+ -- Specifically, the posts around this point are relevant,as they are regarding this resource: https://discord.com/channels/801330706252038164/801411291024457778/1361397061123051832
6
+ -- Use on production servers is still discouraged, unless you're satisfied with what you see and think it's already better than MTA's parachuting up until now
7
+ -- Special thanks to -ffs-Plasma (initial version, written from scratch, and his research on original SA behavior/Parachute SCM)
8
+ --]]
9
+
10
+ local strParachuteState = " NONE" ;
11
+ local strPlayerState = " GROUND" ;
12
+ local strPlayerAction = " NONE" ;
13
+ local bHasParachute = false ;
14
+ local uParachuteSound = nil ;
15
+ local uParachuteObject = nil ;
16
+ local uParachuteCollision = nil ;
17
+ local iParachuteAnim = false ;
18
+ local fParachuteX = 0 ;
19
+ local fParachuteY = 0 ;
20
+ local fParachuteZ = 0 ;
21
+ local fParachuteYaw = 0 ;
22
+ local fParachuteRoll = 0 ;
23
+ local fParachutePitch = 0 ;
24
+ local fRotationX , fRotationY , fRotationZ = 0 , 0 , 0 ;
25
+ local fEasingProgress = 0 ;
26
+ local fEasingProgress2 = 0 ;
27
+ local fEasingProgress3 = 0 ;
28
+
29
+ local fAccelerate = 0.1 ;
30
+
31
+ local function handleParachuteLogic ()
32
+ if (getElementHealth (localPlayer ) > 0 ) then
33
+ -- get pos/rot/vel/ground from localPlayer
34
+ local fPX , fPY , fPZ = getElementPosition (localPlayer );
35
+ local fRX , fRY , fRZ = getElementRotation (localPlayer );
36
+ local fVX , fVY , fVZ = getElementVelocity (localPlayer );
37
+ local fGroundPosition = getGroundPosition (fPX , fPY , fPZ );
38
+
39
+ -- get player input
40
+ local fControlForwards = getPedAnalogControlState (localPlayer , " forwards" );
41
+ local fControlBackwards = getPedAnalogControlState (localPlayer , " backwards" );
42
+ local fControlLeft = getPedAnalogControlState (localPlayer , " left" );
43
+ local fControlRight = getPedAnalogControlState (localPlayer , " right" );
44
+
45
+ -- movement/direction velocity
46
+ local fMVX , fMVY , fMVZ , fMRZ = 0 , 0 , 0 , 0 ;
47
+
48
+ -- check if player got parachute
49
+ if (getPedWeapon (localPlayer , 11 ) ~= 0 ) then
50
+ if (getPedTotalAmmo (localPlayer , 11 ) > 0 ) then
51
+ bHasParachute = true ;
52
+ end
53
+ end
54
+
55
+ -- if we do anything with parachute, disable weapon switching
56
+ if (strParachuteState ~= " NONE" ) then
57
+ toggleControl (" next_weapon" , false );
58
+ toggleControl (" previous_weapon" , false );
59
+ end
60
+
61
+ -- can we go to freefall/skydive
62
+ if (strPlayerState == " GROUND" and bHasParachute ) then
63
+ fRotationX , fRotationY , fRotationZ = getElementRotation (localPlayer );
64
+
65
+ if (not isPedOnGround (localPlayer ) and not getPedContactElement (localPlayer )) then
66
+ if (fVZ < - 0.1 ) then
67
+ if ((fPZ - fGroundPosition ) > 20 ) then
68
+ if (isElement (uParachuteSound )) then destroyElement (uParachuteSound ) end
69
+ setPedWeaponSlot (localPlayer , 11 );
70
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive" , - 1 , true , true , false , false );
71
+ uParachuteSound = playSFX (" genrl" , 137 , 20 , true );
72
+ strParachuteState = " READY" ;
73
+ strPlayerState = " FREEFALL" ;
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ -- player is in freefall aka. skydive
80
+ if (strPlayerState == " FREEFALL" ) then
81
+ if (fControlForwards ~= 0 ) then
82
+ if (strPlayerAction ~= " FORWARDS" ) then
83
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive_accel" , - 2 , true , true , false , false );
84
+ end
85
+
86
+ if (fControlLeft ~= 0 ) then
87
+ fRotationZ = fRotationZ - 1 ;
88
+ elseif (fControlRight ~= 0 ) then
89
+ fRotationZ = fRotationZ + 1 ;
90
+ end
91
+
92
+ if (fRotationZ < 0 ) then
93
+ fRotationZ = fRotationZ + 360 ;
94
+ elseif (fRotationZ > 360 ) then
95
+ fRotationZ = fRotationZ - 360 ;
96
+ end
97
+
98
+ local fPitch = interpolateBetween (0 , 0 , 0 , 50 , 0 , 0 , fEasingProgress , " Linear" );
99
+
100
+ fEasingProgress = fEasingProgress + 0.01
101
+
102
+ if (fEasingProgress > 1 ) then
103
+ fEasingProgress = 1 ;
104
+ end
105
+
106
+ setElementRotation (localPlayer , fPitch , 0 , fRotationZ );
107
+
108
+ strPlayerAction = " FORWARDS" ;
109
+ elseif (fControlBackwards ~= 0 ) then
110
+ if (strPlayerAction ~= " BACKWARDS" ) then
111
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive" , - 2 , true , true , false , false );
112
+ end
113
+
114
+ if (fControlLeft ~= 0 ) then
115
+ fRotationZ = fRotationZ - 1 ;
116
+ elseif (fControlRight ~= 0 ) then
117
+ fRotationZ = fRotationZ + 1 ;
118
+ end
119
+
120
+ if (fRotationZ < 0 ) then
121
+ fRotationZ = fRotationZ + 360 ;
122
+ elseif (fRotationZ > 360 ) then
123
+ fRotationZ = fRotationZ - 360 ;
124
+ end
125
+
126
+ local fPitch = interpolateBetween (0 , 0 , 0 , 50 , 0 , 0 , fEasingProgress2 , " Linear" );
127
+
128
+ fEasingProgress2 = fEasingProgress2 + 0.01 ;
129
+
130
+ if (fEasingProgress2 > 1 ) then
131
+ fEasingProgress2 = 1 ;
132
+ end
133
+
134
+ setElementRotation (localPlayer , fPitch * - 1 , 0 , fRotationZ );
135
+
136
+ strPlayerAction = " BACKWARDS" ;
137
+ else
138
+ if (fControlLeft ~= 0 ) then
139
+ if (strPlayerAction ~= " LEFT" ) then
140
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive_l" , - 2 , true , true , false , false );
141
+ end
142
+
143
+ fRotationZ = fRotationZ - 1 ;
144
+
145
+ if (fRotationZ < 0 ) then
146
+ fRotationZ = fRotationZ + 360 ;
147
+ end
148
+
149
+ setElementRotation (localPlayer , 0 , 0 , fRotationZ );
150
+
151
+ strPlayerAction = " LEFT" ;
152
+ elseif (fControlRight ~= 0 ) then
153
+ if (strPlayerAction ~= " RIGHT" ) then
154
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive_r" , - 2 , true , true , false , false );
155
+ end
156
+
157
+ fRotationZ = fRotationZ + 1 ;
158
+
159
+ if (fRotationZ > 360 ) then
160
+ fRotationZ = fRotationZ - 360 ;
161
+ end
162
+
163
+ setElementRotation (localPlayer , 0 , 0 , fRotationZ );
164
+
165
+ strPlayerAction = " RIGHT" ;
166
+ else
167
+ if (strPlayerAction ~= " NONE" ) then
168
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive" , - 2 , true , true , false , false );
169
+ end
170
+
171
+ strPlayerAction = " NONE" ;
172
+ end
173
+
174
+ if (fEasingProgress > 0 ) then
175
+ local fPitch = interpolateBetween (0 , 0 , 0 , 50 , 0 , 0 , fEasingProgress , " Linear" );
176
+
177
+ fEasingProgress = fEasingProgress - 0.01 ;
178
+
179
+ if (fEasingProgress < 0 ) then
180
+ fEasingProgress = 0 ;
181
+ end
182
+
183
+ setElementRotation (localPlayer , fPitch , 0 , fRotationZ );
184
+ end
185
+
186
+ if (fEasingProgress2 > 0 ) then
187
+ local fPitch = interpolateBetween (0 , 0 , 0 , 50 , 0 , 0 , fEasingProgress2 , " Linear" );
188
+
189
+ fEasingProgress2 = fEasingProgress2 - 0.01 ;
190
+
191
+ if (fEasingProgress2 < 0 ) then
192
+ fEasingProgress2 = 0 ;
193
+ end
194
+
195
+ setElementRotation (localPlayer , fPitch * - 1 , 0 , fRotationZ );
196
+ end
197
+ end
198
+
199
+ -- Handle player velocity/rotation (Not sure how yet, block commented out)
200
+
201
+ --[[
202
+
203
+ -- X
204
+ fParachuteX = fParachuteX / 4.267;
205
+ fParachuteX = fParachuteX - fParachuteRoll;
206
+ fParachuteX = fParachuteX / 20;
207
+ --fParachuteX = fParachuteX * para_time_step;
208
+ fParachuteRoll = fParachuteRoll + fParachuteX;
209
+
210
+ fParachuteX = fParachuteRoll / 5;
211
+ --fParachuteX = fParachuteX * para_time_step;
212
+ fParachuteYaw = fParachuteX;
213
+
214
+ if(fParachuteYaw > 180) then
215
+ fParachuteYaw = fParachuteYaw - 360;
216
+ end
217
+
218
+ if(fParachuteYaw < -180) then
219
+ fParachuteYaw = fParachuteYaw + 360;
220
+ end
221
+
222
+ -- Y
223
+ fParachuteX = fParachuteX / 4.267;
224
+ fParachuteX = fParachuteX - fParachutePitch;
225
+ fParachuteX = fParachuteX / 20;
226
+ --fParachuteX = fParachuteX * para_time_step;
227
+ fParachutePitch = fParachutePitch + fParachuteX;
228
+ --]]
229
+
230
+ -- player opening parachute
231
+ if (getControlState (localPlayer , " fire" ) and strParachuteState == " READY" ) then
232
+ strPlayerState = " ACTION" ;
233
+ setPedAnimation (localPlayer , " parachute" , " para_open" , - 2 , false , false , false , true );
234
+ setPedAnimationSpeed (localPlayer , " para_open" , 8 );
235
+
236
+ if (isElement (uParachuteSound )) then destroyElement (uParachuteSound ) end
237
+ uParachuteSound = playSFX (" genrl" , 137 , 21 , true );
238
+
239
+ setTimer (function ()
240
+ if (isElement (uParachuteSound )) then destroyElement (uParachuteSound ) end
241
+ uParachuteSound = playSFX (" genrl" , 137 , 66 , false );
242
+ end , 1100 , 1 );
243
+ end
244
+
245
+ -- player hit the ground without opening parachute
246
+ if ((fPZ - fGroundPosition ) < 2 ) then
247
+ strPlayerState = " HITGROUND" ;
248
+ strParachuteState = " NOTREADY" ;
249
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive_die" , - 1 , false , false , false , false );
250
+ setTimer (cleanupParachute , 2000 , 1 );
251
+ end
252
+ end
253
+
254
+ -- player opening parachute
255
+ if (strPlayerState == " ACTION" ) then
256
+ -- is it too late?
257
+ if ((fPZ - fGroundPosition ) < 2 ) then
258
+ strPlayerState = " HITGROUND" ;
259
+ strParachuteState = " NOTREADY" ;
260
+ setPedAnimation (localPlayer , " parachute" , " fall_skydive_die" , - 1 , false , false , false , false );
261
+ setTimer (cleanupParachute , 2000 , 1 );
262
+ else
263
+ if (strParachuteState ~= " OPENING" ) then
264
+ strParachuteState = " OPENING" ;
265
+
266
+ -- prepare parachute opening animation
267
+ uParachuteObject = createObject (1310 , 0 , 0 , 0 );
268
+ attachElements (uParachuteObject , localPlayer );
269
+ setObjectScale (uParachuteObject , 0 );
270
+ -- SCM: PLAY_OBJECT_ANIM parac para_open_o PARACHUTE 1000.0 0 1
271
+ iParachuteAnim = getTickCount ();
272
+
273
+ setTimer (function ()
274
+ strPlayerState = " GLIDING" ;
275
+ strParachuteState = " OPENED" ;
276
+ end , 1000 , 1 );
277
+ end
278
+ end
279
+ end
280
+
281
+ -- do parachute opening animation
282
+ if (iParachuteAnim ) then
283
+ if ((getTickCount () - iParachuteAnim ) < 500 ) then
284
+ setObjectScale (uParachuteObject , (getTickCount () - iParachuteAnim ) / 500 );
285
+ else
286
+ setObjectScale (uParachuteObject , 1 );
287
+ iParachuteAnim = false ;
288
+
289
+ -- create parachute collision
290
+ uParachuteCollision = createObject (3060 , 0 , 0 , 0 );
291
+ setElementAlpha (uParachuteCollision , 0 );
292
+ attachElements (uParachuteCollision , uParachuteObject );
293
+ -- SCM: SET_OBJECT_DYNAMIC para_col TRUE
294
+ -- SCM: SET_OBJECT_RECORDS_COLLISIONS para_col TRUE
295
+ end
296
+ end
297
+
298
+ -- player is gliding with parachute
299
+ if (strPlayerState == " GLIDING" ) then
300
+ setPedAnimation (localPlayer , " parachute" , " para_float" , - 2 , true , false , false , true );
301
+ -- SCM: PLAY_OBJECT_ANIM parac para_float_o PARACHUTE 1.0 1 1
302
+
303
+ if (fControlForwards ~= 0 and strPlayerAction ~= " FORWARDS" ) then
304
+ strPlayerAction = " FORWARDS" ;
305
+ setPedAnimation (localPlayer , " parachute" , " para_float" , - 2 , true , false , false , true );
306
+ -- SCM: PLAY_OBJECT_ANIM parac para_float_o PARACHUTE 1.0 1 1
307
+ elseif (fControlBackwards ~= 0 and strPlayerAction ~= " BACKWARDS" ) then
308
+ strPlayerAction = " BACKWARDS" ;
309
+ setPedAnimation (localPlayer , " parachute" , " para_decel" , - 2 , true , false , false , true );
310
+ -- SCM: PLAY_OBJECT_ANIM parac para_decel_o PARACHUTE 1.0 1 1
311
+ elseif (fControlLeft ~= 0 and strPlayerAction ~= " LEFT" ) then
312
+ strPlayerAction = " LEFT" ;
313
+ setPedAnimation (localPlayer , " parachute" , " para_steerl" , - 2 , true , false , false , true );
314
+ -- SCM: PLAY_OBJECT_ANIM parac para_steerL_o PARACHUTE 1.0 1 1
315
+ elseif (fControlRight ~= 0 and strPlayerAction ~= " RIGHT" ) then
316
+ strPlayerAction = " RIGHT" ;
317
+ setPedAnimation (localPlayer , " parachute" , " para_steerr" , - 2 , true , false , false , true );
318
+ -- SCM: PLAY_OBJECT_ANIM parac para_steerR_o PARACHUTE 1.0 1 1
319
+ else
320
+ if (strPlayerAction ~= " NONE" ) then
321
+ setPedAnimation (localPlayer , " parachute" , " para_float" , - 2 , true , false , false , true );
322
+ -- SCM: PLAY_OBJECT_ANIM parac para_float_o PARACHUTE 1.0 1 1
323
+ end
324
+
325
+ strPlayerAction = " NONE" ;
326
+ end
327
+
328
+ -- SCM:
329
+ -- IF HAS_OBJECT_COLLIDED_WITH_ANYTHING para_col
330
+ -- PLAY_OBJECT_ANIM parac para_rip_loop_o PARACHUTE 8.0 1 1
331
+
332
+ --[[ setElementVelocity(localPlayer, x, y, z);
333
+ setElementRotation(localPlayer, 0, 0, yaw);
334
+
335
+ -- player landed
336
+ if (fVZ > -0.1) then
337
+ strPlayerState = "LANDED";
338
+ strParachuteState = "CLOSING";
339
+ end--]]
340
+ end
341
+
342
+ -- player landed
343
+ if (strPlayerState == " LANDED" ) then
344
+
345
+ end
346
+ end
347
+ end
348
+ addEventHandler (" onClientRender" , root , handleParachuteLogic );
349
+
350
+ function cleanupParachute (bLandedGood )
351
+ iParachuteAnim = false ;
352
+ bHasParachute = false ;
353
+ strParachuteState = " NONE" ;
354
+ strPlayerState = " GROUND" ;
355
+ strPlayerAction = " NONE" ;
356
+
357
+ if (isElement (uParachuteCollision )) then destroyElement (uParachuteCollision ) end ;
358
+ if (isElement (uParachuteObject )) then destroyElement (uParachuteObject ) end ;
359
+ if (isElement (uParachuteSound )) then destroyElement (uParachuteSound ) end ;
360
+
361
+ toggleControl (" next_weapon" , true );
362
+ toggleControl (" previous_weapon" , true );
363
+
364
+ if (not bLandedGood ) then
365
+ -- todo: remove weapon from player via server
366
+ -- takeWeapon(client, 46);
367
+ end
368
+ end
0 commit comments