├── .gitattributes ├── .gitignore ├── README.md ├── addons └── AR_AdvancedRappelling │ ├── $PBOPREFIX$ │ ├── anims │ ├── Rup_RopeFX_01_aim.rtm │ ├── Rup_RopeFX_01_aim1.rtm │ ├── Rup_RopeFX_01_aimfrompistol.rtm │ ├── Rup_RopeFX_01_aimfrompistol_end.rtm │ ├── Rup_RopeFX_01_aimpistol.rtm │ ├── Rup_RopeFX_01_aimpistol1.rtm │ ├── Rup_RopeFX_01_aimtopistol.rtm │ ├── Rup_RopeFX_01_aimtopistol_end.rtm │ ├── Rup_RopeFX_01_die.rtm │ ├── Rup_RopeFX_01_idle.rtm │ ├── Rup_RopeFX_01_idle1.rtm │ ├── Rup_RopeFX_01_idlepistol.rtm │ └── Rup_RopeFX_01_idlepistol1.rtm │ ├── cfgAnimations.hpp │ ├── config.cpp │ ├── functions │ └── fn_advancedRappellingInit.sqf │ └── sounds │ ├── AR_Rappel_End.ogg │ ├── AR_Rappel_Loop.ogg │ └── AR_Rappel_Start.ogg ├── keys └── AdvancedRappelling.bikey ├── logo.paa ├── logo.png ├── logo.psd ├── mod.cpp ├── screenshots ├── ss1.JPG ├── ss2.JPG ├── ss3.JPG └── ss4.JPG ├── steamLogo.jpg └── steamLogo.psd /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | *.sqf eol=crlf 20 | *.sqm eol=crlf 21 | *.ext eol=crlf 22 | *.hpp eol=crlf 23 | *.cpp eol=crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | *.pbo 49 | addons/SA_AdvancedSlingLoading.pbo.AdvancedSlingLoading.bisign 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Rappelling 2 | 3 | Adds support for helicopter rappelling. SP & MP Compatible. 4 | 5 | **Features:** 6 | 7 | - Rappel up to 6 players or AI from any helicopter at the same time (depending on helicopter size) 8 | - Enhanced rope physics. Takes into account wind speeds (from the rotor and environment) and air resistance. Players will swing around if the helicopter doesn't stay still. 9 | - Players control when and how quickly to descend down the rope using the "move backward" key 10 | - Supports rappelling onto tops of buildings, through trees, etc 11 | - Command AI in your group to rappel from a helicopter. AI will automatically descend the rope once told to rappel 12 | 13 | **Directions:** 14 | 15 | - Get into any helicopter (not as pilot) 16 | - Once more than 5m off the ground, actions become available to rappel either yourself or your AI units 17 | - Once you are rappelling, press the "move backwards" key to descend down the rope (note: AI will auto-descend) 18 | 19 | **Installation:** 20 | 21 | 1. Subscribe via steam: http://steamcommunity.com/sharedfiles/filedetails/?id=713709341 or download latest release from https://github.com/sethduda/AdvancedRappelling/releases 22 | 2. If installing this on a server, add the addon to the -serverMod command line option. It's only needed on the server side. Clients down need it. (However, if clients want to hear the nice rappelling sounds effects, they can optionally install it locally) 23 | 24 | **Notes for Mission Makers:** 25 | 26 | You can customize which classes of vehicles support rappelling by setting the AR_SUPPORTED_VEHICLES_OVERRIDE variable in an init.sqf file. 27 | 28 | ```AR_SUPPORTED_VEHICLES_OVERRIDE = [ "CUP_CH47F_base", "RHS_CH_47F" ]; ``` 29 | 30 | The example above will only allow rappelling from vehicles of class CUP_CH47F_base and RHS_CH_47F. 31 | 32 | You can disable shooting whlie rappelling by setting the AR_DISABLE_SHOOTING_OVERRIDE varaible in an init.sqf file. Defaults to false (shooting enabled). 33 | 34 | ```AR_DISABLE_SHOOTING_OVERRIDE = true; ``` 35 | 36 | You can limit the number of rappell positions (for all helicopters) using the AR_MAX_RAPPEL_POINTS_OVERRIDE variable in an init.sqf file. Defaults to 6. You can set any value from 1 to 6. 37 | 38 | ```AR_MAX_RAPPEL_POINTS_OVERRIDE = 2;``` 39 | 40 | You can define custom rappel points instead of using the default 6 rappel points by using the AP_CUSTOM_RAPPEL_POINTS variable. You can either specify [x,y,z] model positions or memory point names. Define the AP_CUSTOM_RAPPEL_POINTS variable in your init.sqf file. 41 | 42 | Here's an example mixing both memory point names and [x,y,z] model positions. You would put this in an init.sqf file. 43 | 44 | ``` 45 | AP_CUSTOM_RAPPEL_POINTS = [ 46 | ["CUP_CH47F_base",["slingload0",[1.2,1.0,0.5],"fastrope0"]], 47 | ["RHS_CH_47F", ["slingload0","slingload1","fastrope0"]] 48 | ]; 49 | ``` 50 | 51 | In the example above, all vehicles of class type CUP_CH47F_base will use the rappel points defined by memory point slingload0, model position [1.2,1.0,0.5] and memory point fastrope0. All vehicles of class RHS_CH_47F will use rappel points defined by memory points slingload0, slingload1, and fastrope0. All other vehicles will use the default 6 rappel points. 52 | 53 | If anyone works on heli models and would like their heli's rappel points pre-defined in my addon, let me know. 54 | 55 | You can have AI auto-rappel from a helicopter using the following script (all units in the cargo seats will rappel): 56 | 57 | ```[HELI_NAME] call AR_Rappel_All_Cargo ``` 58 | 59 | This function will rappel the cargo units at 25m at the heli's current position. If the heli is currently moving, it will stop so units can rappel. 60 | 61 | If you want more control, there are addtional parameters you can set: 62 | 63 | ```[HELI_NAME,RAPPEL_HEIGHT,POSITION_ASL] call AR_Rappel_All_Cargo ``` 64 | 65 | RAPPEL_HEIGHT: height in meters to rappel 66 | POSITION_ASL: Exact position ASL where you want the units to rappel to. This script will get them within ~1m of that position. 67 | 68 | **Not working on your server?** 69 | 70 | Make sure you have the mod listed in the -mod or -serverMod command line option. Only -serverMod is required for this addon. If still not working, check your server log to make sure the addon is found. 71 | 72 | **FAQ** 73 | 74 | *This addon is only required on the server - is it going to slow down my server?* 75 | 76 | No - while this addon is server-side only, it installs itself on all clients without them downloading the addon. Most of the time, the rappelling code actually runs client-side, even though you installed the addon only on the server. Magic! 77 | 78 | *Battleye kicks me when I try to do xyz. What do I do?* 79 | 80 | You need to configure Battleye rules on your server. Below are the files you need to configure: 81 | 82 | setvariable.txt 83 | 84 | Add the following exclusions to the end of all lines starting with 4, 5, 6, or 7 if they contain "" (meaning applies to all values): 85 | 86 | !"AR_" 87 | 88 | setvariableval.txt 89 | 90 | If you have any lines starting with 4, 5, 6, or 7 and they contain "" (meaning applies to all values) it's not going to work. Either remove the line or explicitly define the values you want to kick. Since the values of the variables above can vary, I don't know of a good way to define an exclusion rule. 91 | 92 | Also, it's possible there are other battleye filter files that can cause issues. If you check your battleye logs you can figure out which file is causing a problem. 93 | 94 | *The rappelling action appears while in a heli, but do nothing when I select them. How do I fix that?* 95 | 96 | Most likely your server is setup with a white list for remote executions. In order to fix this, you need to modify your mission's description.ext file, adding the following CfgRemoteExec rules. If using InfiStar you should edit your cfgremoteexec.hpp instead of the description.ext file. See https://community.bistudio.com/wiki/Arma_3_Remote_Execution for more details on CfgRemoteExec. 97 | 98 | ``` 99 | class CfgRemoteExec 100 | { 101 | class Functions 102 | { 103 | class AR_Client_Rappel_From_Heli { allowedTargets=0; }; 104 | class AR_Hint { allowedTargets=1; }; 105 | class AR_Hide_Object_Global { allowedTargets=2; }; 106 | class AR_Enable_Rappelling_Animation { allowedTargets=2; }; 107 | class AR_Rappel_From_Heli { allowedTargets=2; }; 108 | }; 109 | }; 110 | ``` 111 | 112 | **Issues & Feature Requests** 113 | 114 | https://github.com/sethduda/AdvancedRappelling/issues 115 | 116 | If anyone wants to help fix any of these, please let me know. You can fork the repo and create a pull request. 117 | 118 | **Special Thanks for Testing & Support:** 119 | 120 | - Stay Alive Tactical Team (http://sa.clanservers.com) 121 | - Boosh and Beachhead 122 | 123 | --- 124 | 125 | The MIT License (MIT) 126 | 127 | Copyright (c) 2016 Seth Duda 128 | 129 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 130 | 131 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 132 | 133 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 134 | -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/$PBOPREFIX$: -------------------------------------------------------------------------------- 1 | AR_AdvancedRappelling -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aim.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aim.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aim1.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aim1.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimfrompistol.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimfrompistol.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimfrompistol_end.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimfrompistol_end.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimpistol.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimpistol.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimpistol1.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimpistol1.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimtopistol.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimtopistol.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimtopistol_end.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_aimtopistol_end.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_die.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_die.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idle.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idle.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idle1.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idle1.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idlepistol.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idlepistol.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idlepistol1.rtm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/anims/Rup_RopeFX_01_idlepistol1.rtm -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/cfgAnimations.hpp: -------------------------------------------------------------------------------- 1 | //Animations by Ruppertle 2 | 3 | class CfgMovesBasic 4 | { 5 | class DefaultDie; 6 | class ManActions 7 | { 8 | AR_01="AR_01_Idle"; 9 | 10 | }; 11 | class Actions 12 | { 13 | class RifleStandActions; 14 | class AR_BaseActions: RifleStandActions 15 | { 16 | AdjustF=""; 17 | AdjustB=""; 18 | AdjustL=""; 19 | AdjustR=""; 20 | AdjustLF=""; 21 | AdjustLB=""; 22 | AdjustRB=""; 23 | AdjustRF=""; 24 | agonyStart=""; 25 | agonyStop=""; 26 | medicStop=""; 27 | medicStart=""; 28 | medicStartUp=""; 29 | medicStartRightSide=""; 30 | GestureAgonyCargo=""; 31 | grabCarry=""; 32 | grabCarried=""; 33 | grabDrag=""; 34 | grabDragged=""; 35 | carriedStill=""; 36 | released=""; 37 | releasedBad=""; 38 | Stop=""; 39 | StopRelaxed=""; 40 | TurnL=""; 41 | TurnR=""; 42 | TurnLRelaxed=""; 43 | TurnRRelaxed=""; 44 | ReloadMagazine=""; 45 | ReloadMGun=""; 46 | ReloadRPG="ReloadRPG"; 47 | ReloadMortar=""; 48 | WalkF=""; 49 | WalkLF=""; 50 | WalkRF=""; 51 | WalkL=""; 52 | WalkR=""; 53 | WalkLB=""; 54 | WalkRB=""; 55 | WalkB=""; 56 | PlayerWalkF=""; 57 | PlayerWalkLF=""; 58 | PlayerWalkRF=""; 59 | PlayerWalkL=""; 60 | PlayerWalkR=""; 61 | PlayerWalkLB=""; 62 | PlayerWalkRB=""; 63 | PlayerWalkB=""; 64 | SlowF=""; 65 | SlowLF=""; 66 | SlowRF=""; 67 | SlowL=""; 68 | SlowR=""; 69 | SlowLB=""; 70 | SlowRB=""; 71 | SlowB=""; 72 | PlayerSlowF=""; 73 | PlayerSlowLF=""; 74 | PlayerSlowRF=""; 75 | PlayerSlowL=""; 76 | PlayerSlowR=""; 77 | PlayerSlowLB=""; 78 | PlayerSlowRB=""; 79 | PlayerSlowB=""; 80 | FastF=""; 81 | FastLF=""; 82 | FastRF=""; 83 | FastL=""; 84 | FastR=""; 85 | FastLB=""; 86 | FastRB=""; 87 | FastB=""; 88 | TactF=""; 89 | TactLF=""; 90 | TactRF=""; 91 | TactL=""; 92 | TactR=""; 93 | TactLB=""; 94 | TactRB=""; 95 | TactB=""; 96 | PlayerTactF=""; 97 | PlayerTactLF=""; 98 | PlayerTactRF=""; 99 | PlayerTactL=""; 100 | PlayerTactR=""; 101 | PlayerTactLB=""; 102 | PlayerTactRB=""; 103 | PlayerTactB=""; 104 | EvasiveLeft=""; 105 | EvasiveRight=""; 106 | startSwim=""; 107 | surfaceSwim=""; 108 | bottomSwim=""; 109 | StopSwim=""; 110 | startDive=""; 111 | SurfaceDive=""; 112 | BottomDive=""; 113 | StopDive=""; 114 | Down=""; 115 | Up=""; 116 | PlayerStand=""; 117 | PlayerCrouch=""; 118 | PlayerProne=""; 119 | Lying=""; 120 | Stand=""; 121 | Combat=""; 122 | Crouch=""; 123 | CanNotMove=""; 124 | Civil=""; 125 | CivilLying=""; 126 | FireNotPossible=""; 127 | WeaponOn=""; 128 | WeaponOff=""; 129 | Default=""; 130 | JumpOff=""; 131 | StrokeFist=""; 132 | StrokeGun=""; 133 | SitDown=""; 134 | Salute=""; 135 | saluteOff=""; 136 | GetOver=""; 137 | Diary=""; 138 | Surrender=""; 139 | Gear=""; 140 | BinocOn=""; 141 | BinocOff=""; 142 | PutDown=""; 143 | PutDownEnd=""; 144 | Medic=""; 145 | MedicOther=""; 146 | Treated=""; 147 | LadderOnDown=""; 148 | LadderOnUp=""; 149 | LadderOff=""; 150 | LadderOffTop=""; 151 | LadderOffBottom=""; 152 | PrimaryWeapon=""; 153 | SecondaryWeapon=""; 154 | Binoculars=""; 155 | StartFreefall = ""; 156 | FDStart = ""; 157 | useFastMove = 0; 158 | stance = "ManStanceUndefined"; 159 | }; 160 | class AR_01_Actions: AR_BaseActions 161 | { 162 | upDegree="ManPosCombat"; 163 | stop="AR_01_Aim"; 164 | stopRelaxed="AR_01_Aim"; 165 | default="AR_01_Aim"; 166 | Stand="AR_01_Idle"; 167 | HandGunOn="AR_01_Aim_Pistol"; 168 | PrimaryWeapon="AR_01_Aim"; 169 | SecondaryWeapon=""; 170 | Binoculars=""; 171 | die="AR_01_Die"; 172 | Unconscious="AR_01_Die"; 173 | civil=""; 174 | }; 175 | class AR_01_DeadActions: AR_BaseActions 176 | { 177 | stop="AR_01_Die"; 178 | default="AR_01_Die"; 179 | die="AR_01_Die"; 180 | Unconscious="AR_01_Die"; 181 | }; 182 | class AR_01_IdleActions: AR_01_Actions 183 | { 184 | upDegree="ManPosStand"; 185 | stop="AR_01_Idle"; 186 | stopRelaxed="AR_01_Idle"; 187 | default="AR_01_Idle"; 188 | Combat="AR_01_Aim"; 189 | fireNotPossible="AR_01_Aim"; 190 | PlayerStand="AR_01_Aim"; 191 | }; 192 | class AR_01_PistolActions: AR_01_Actions 193 | { 194 | upDegree="ManPosHandGunStand"; 195 | stop="AR_01_Aim_Pistol"; 196 | stopRelaxed="AR_01_Aim_Pistol"; 197 | default="AR_01_Aim_Pistol"; 198 | throwGrenade[]= 199 | { 200 | "GestureThrowGrenadePistol", 201 | "Gesture" 202 | }; 203 | Stand="AR_01_Idle_Pistol"; 204 | die="AR_01_Die_Pistol"; 205 | Unconscious="AR_01_Die_Pistol"; 206 | }; 207 | class AR_01_IdlePistolActions: AR_01_Actions 208 | { 209 | upDegree="ManPosHandGunStand"; 210 | stop="AR_01_Idle_Pistol"; 211 | stopRelaxed="AR_01_Idle_Pistol"; 212 | default="AR_01_Idle_Pistol"; 213 | Combat="AR_01_Aim_Pistol"; 214 | fireNotPossible="AR_01_Aim_Pistol"; 215 | PlayerStand="AR_01_Aim_Pistol"; 216 | die="AR_01_Die_Pistol"; 217 | Unconscious="AR_01_Die_Pistol"; 218 | }; 219 | }; 220 | }; 221 | class CfgMovesMaleSdr: CfgMovesBasic 222 | { 223 | class States 224 | { 225 | class Crew; 226 | class AmovPercMstpSrasWrflDnon; 227 | class AmovPercMstpSrasWpstDnon; 228 | class AmovPercMstpSoptWbinDnon; 229 | class AmovPpneMstpSrasWrflDnon_AmovPpneMstpSrasWpstDnon; 230 | class AmovPpneMstpSrasWrflDnon_AmovPpneMstpSrasWpstDnon_end; 231 | class AmovPpneMstpSrasWpstDnon_AmovPpneMstpSrasWrflDnon; 232 | class AmovPpneMstpSrasWpstDnon_AmovPpneMstpSrasWrflDnon_end; 233 | class ar_cargo_marksman: AmovPercMstpSrasWrflDnon 234 | { 235 | }; 236 | class ar_cargo_base: ar_cargo_marksman 237 | { 238 | variantsPlayer[]={}; 239 | variantsAI[]={}; 240 | enableMissile = 0; 241 | enableBinocular = 0; 242 | }; 243 | class ar_cargo_base_Rope: ar_cargo_base 244 | { 245 | ignoreMinPlayTime[] = {"Unconscious"}; 246 | leaning = "AR_aimingDefault_Rope"; 247 | }; 248 | class ar_cargo_base_idle: ar_cargo_base 249 | { 250 | weaponLowered=1; 251 | enableOptics=0; 252 | disableWeapons=1; 253 | disableWeaponsLong=1; 254 | variantsPlayer[]={}; 255 | variantsAI[]={}; 256 | }; 257 | class ar_cargo_basepistol: AmovPercMstpSrasWpstDnon 258 | { 259 | variantsPlayer[]={}; 260 | variantsAI[]={}; 261 | enableMissile = 0; 262 | enableBinocular = 0; 263 | }; 264 | class ar_cargo_base_idle_pistol: ar_cargo_basepistol 265 | { 266 | weaponLowered=1; 267 | enableOptics=0; 268 | disableWeapons=1; 269 | disableWeaponsLong=1; 270 | }; 271 | class AR_01_Aim: ar_cargo_base_Rope 272 | { 273 | actions="AR_01_Actions"; 274 | leftHandIKCurve[]={1}; 275 | minPlayTime = 0.1; 276 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aim.rtm"; /// what file is going to be played in this state 277 | speed=100000; 278 | ConnectTo[]={}; 279 | InterpolateTo[]= 280 | { 281 | "AR_01_Idle", 282 | 0.1, 283 | "AR_01_Aim_ToPistol", 284 | 0.1, 285 | "AR_01_Die", 286 | 0.1 287 | }; 288 | variantsAI[]= 289 | { 290 | "AR_01_Aim_Idling", 291 | 1 292 | }; 293 | variantsPlayer[]= 294 | { 295 | "AR_01_Aim_Idling", 296 | 1 297 | }; 298 | }; 299 | class AR_01_Aim_No_Actions : AR_01_Aim 300 | { 301 | actions="NoActions"; 302 | variantsPlayer[]={}; 303 | variantsAI[]={}; 304 | ConnectTo[]={}; 305 | InterpolateTo[]={}; 306 | }; 307 | class AR_01_Aim_Idling: AR_01_Aim 308 | { 309 | variantsPlayer[]={}; 310 | headBobStrength=0; 311 | soundEnabled=1; 312 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aim1.rtm"; 313 | speed=-8; 314 | ConnectTo[]= 315 | { 316 | "AR_01_Aim", 317 | 0.1 318 | }; 319 | }; 320 | class AR_01_Idle: ar_cargo_base_idle 321 | { 322 | actions="AR_01_IdleActions"; 323 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_idle.rtm"; 324 | speed=100000; 325 | minPlayTime = 0.1; 326 | aiming="aimingDefault"; 327 | leftHandIKCurve[]={0}; 328 | InterpolateTo[]= 329 | { 330 | "AR_01_Aim", 331 | 0.1, 332 | "AR_01_Aim_ToPistol", 333 | 0.1, 334 | "AR_01_Die", 335 | 0.1 336 | }; 337 | variantsAI[]= 338 | { 339 | "AR_01_Idle_Idling", 340 | 1 341 | }; 342 | variantsPlayer[]= 343 | { 344 | "AR_01_Idle_Idling", 345 | 1 346 | }; 347 | }; 348 | class AR_01_Idle_No_Actions : AR_01_Idle 349 | { 350 | actions="NoActions"; 351 | variantsPlayer[]={}; 352 | variantsAI[]={}; 353 | ConnectTo[]={}; 354 | InterpolateTo[]={}; 355 | }; 356 | class AR_01_Idle_Idling: AR_01_Idle 357 | { 358 | variantsPlayer[]={}; 359 | headBobStrength=0; 360 | soundEnabled=1; 361 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_idle1.rtm"; 362 | speed=-10; 363 | ConnectTo[]= 364 | { 365 | "AR_01_Idle", 366 | 0.1 367 | }; 368 | }; 369 | class AR_01_Aim_Pistol: ar_cargo_basepistol 370 | { 371 | actions="AR_01_PistolActions"; 372 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aimpistol.rtm"; 373 | aiming="aimingRifleSlingDefault"; 374 | aimingBody="aimingUpRifleSlingDefault"; 375 | speed=100000; 376 | variantsAI[]= 377 | { 378 | "AR_01_Aim_Pistol_Idling", 379 | 1 380 | }; 381 | variantsPlayer[]= 382 | { 383 | "AR_01_Aim_Pistol_Idling", 384 | 1 385 | }; 386 | ConnectTo[]={}; 387 | InterpolateTo[]= 388 | { 389 | "AR_01_Aim_FromPistol", 390 | 0.1, 391 | "AR_01_Idle_Pistol", 392 | 0.2, 393 | "AR_01_Die_Pistol", 394 | 0.5 395 | }; 396 | }; 397 | class AR_01_Aim_Pistol_No_Actions : AR_01_Aim_Pistol 398 | { 399 | actions="NoActions"; 400 | variantsPlayer[]={}; 401 | variantsAI[]={}; 402 | ConnectTo[]={}; 403 | InterpolateTo[]={}; 404 | }; 405 | class AR_01_Aim_Pistol_Idling: AR_01_Aim_Pistol 406 | { 407 | variantsPlayer[]={}; 408 | headBobStrength=0; 409 | soundEnabled=1; 410 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aimpistol1.rtm"; 411 | speed=-8; 412 | ConnectTo[]= 413 | { 414 | "AR_01_Aim_Pistol", 415 | 0.1 416 | }; 417 | }; 418 | class AR_01_Idle_Pistol: ar_cargo_base_idle_pistol 419 | { 420 | actions="AR_01_IdlePistolActions"; 421 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_idlepistol.rtm"; 422 | speed=100000; 423 | aiming="aimingRifleSlingDefault"; 424 | aimingBody="aimingUpRifleSlingDefault"; 425 | InterpolateTo[]= 426 | { 427 | "AR_01_Aim_Pistol", 428 | 0.1, 429 | "AR_01_Aim_FromPistol", 430 | 0.1, 431 | "AR_01_Die_Pistol", 432 | 0.1 433 | }; 434 | variantsAI[]= 435 | { 436 | "AR_01_Idle_Pistol_Idling", 437 | 1 438 | }; 439 | variantsPlayer[]= 440 | { 441 | "AR_01_Idle_Pistol_Idling", 442 | 1 443 | }; 444 | }; 445 | class AR_01_Idle_Pistol_No_Actions : AR_01_Idle_Pistol 446 | { 447 | actions="NoActions"; 448 | variantsPlayer[]={}; 449 | variantsAI[]={}; 450 | ConnectTo[]={}; 451 | InterpolateTo[]={}; 452 | }; 453 | class AR_01_Idle_Pistol_Idling: AR_01_Idle 454 | { 455 | variantsPlayer[]={}; 456 | headBobStrength=0; 457 | soundEnabled=1; 458 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_idlepistol1.rtm"; 459 | speed=-10; 460 | ConnectTo[]= 461 | { 462 | "AR_01_Idle_Pistol", 463 | 0.1 464 | }; 465 | }; 466 | class AR_01_Aim_ToPistol: AmovPpneMstpSrasWrflDnon_AmovPpneMstpSrasWpstDnon 467 | { 468 | actions="AR_01_PistolActions"; 469 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aimtopistol.rtm"; 470 | speed=2; 471 | ConnectTo[]= 472 | { 473 | "AR_01_Aim_ToPistol_End", 474 | 0.1 475 | }; 476 | InterpolateTo[]={}; 477 | }; 478 | class AR_01_Aim_ToPistol_End: AmovPpneMstpSrasWrflDnon_AmovPpneMstpSrasWpstDnon_end 479 | { 480 | actions="AR_01_PistolActions"; 481 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aimtopistol_end.rtm"; 482 | speed=1.875; 483 | ConnectTo[]= 484 | { 485 | "AR_01_Aim_Pistol", 486 | 0.1 487 | }; 488 | InterpolateTo[]={}; 489 | }; 490 | class AR_01_Aim_FromPistol: AmovPpneMstpSrasWpstDnon_AmovPpneMstpSrasWrflDnon 491 | { 492 | actions="AR_01_PistolActions"; 493 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aimFrompistol.rtm"; 494 | speed=2.3076921; 495 | ConnectTo[]= 496 | { 497 | "AR_01_Aim_FromPistol_End", 498 | 0.1 499 | }; 500 | InterpolateTo[]={}; 501 | }; 502 | class AR_01_Aim_FromPistol_End: AmovPpneMstpSrasWpstDnon_AmovPpneMstpSrasWrflDnon_end 503 | { 504 | actions="AR_01_Actions"; 505 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_aimfrompistol_end.rtm"; 506 | aiming="aimingDefault"; 507 | aimingBody="aimingUpDefault"; 508 | speed=2; 509 | leftHandIKCurve[]={0,0,0.5,1}; 510 | ConnectTo[]= 511 | { 512 | "AR_01_Aim", 513 | 0.1 514 | }; 515 | InterpolateTo[]={}; 516 | }; 517 | class AR_01_Die: DefaultDie 518 | { 519 | actions="AR_01_DeadActions"; 520 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_die.rtm"; 521 | speed=1; 522 | looped="false"; 523 | terminal=1; 524 | ragdoll=1; 525 | ConnectTo[]= 526 | { 527 | "Unconscious", 528 | 0.1 529 | }; 530 | InterpolateTo[]={}; 531 | }; 532 | class AR_01_Die_Pistol: AR_01_Die 533 | { 534 | file="\AR_AdvancedRappelling\anims\Rup_RopeFX_01_die.rtm"; 535 | actions="AR_01_DeadActions"; 536 | showHandGun=1; 537 | }; 538 | }; 539 | class BlendAnims; 540 | class BlendAnims: BlendAnims 541 | { 542 | AR_aimingDefault_Rope[] = {"head",0.6,"neck1",0.6,"neck",0.6,"weapon",1,"launcher",1,"RightShoulder",0.8,"RightArm",0.8,"RightArmRoll",1,"RightForeArm",1,"RightForeArmRoll",1,"RightHand",1,"RightHandRing",1,"RightHandPinky1",1,"RightHandPinky2",1,"RightHandPinky3",1,"RightHandRing1",1,"RightHandRing2",1,"RightHandRing3",1,"RightHandMiddle1",1,"RightHandMiddle2",1,"RightHandMiddle3",1,"RightHandIndex1",1,"RightHandIndex2",1,"RightHandIndex3",1,"RightHandThumb1",1,"RightHandThumb2",1,"RightHandThumb3",1,"Spine",0.3,"Spine1",0.4,"Spine2",0.5,"Spine3",0.6}; 543 | }; 544 | }; 545 | -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/config.cpp: -------------------------------------------------------------------------------- 1 | class CfgPatches 2 | { 3 | class AR_AdvancedRappelling 4 | { 5 | units[] = {"AR_AdvancedRappelling"}; 6 | requiredVersion = 1.0; 7 | requiredAddons[] = {"A3_Modules_F"}; 8 | }; 9 | }; 10 | 11 | class CfgNetworkMessages 12 | { 13 | 14 | class AdvancedRappellingRemoteExecClient 15 | { 16 | module = "AdvancedRappelling"; 17 | parameters[] = {"ARRAY","STRING","OBJECT","BOOL"}; 18 | }; 19 | 20 | class AdvancedRappellingRemoteExecServer 21 | { 22 | module = "AdvancedRappelling"; 23 | parameters[] = {"ARRAY","STRING","BOOL"}; 24 | }; 25 | 26 | }; 27 | 28 | class CfgFunctions 29 | { 30 | class SA 31 | { 32 | class AdvancedRappelling 33 | { 34 | file = "\AR_AdvancedRappelling\functions"; 35 | class advancedRappellingInit{postInit=1}; 36 | }; 37 | }; 38 | }; 39 | 40 | class CfgSounds 41 | { 42 | class AR_Rappel_Loop 43 | { 44 | name = "AR_Rappel_Loop"; 45 | sound[] = {"\AR_AdvancedRappelling\sounds\AR_Rappel_Loop.ogg", db+20, 1}; 46 | titles[] = {0,""}; 47 | }; 48 | class AR_Rappel_Start 49 | { 50 | name = "AR_Rappel_Start"; 51 | sound[] = {"\AR_AdvancedRappelling\sounds\AR_Rappel_Start.ogg", db+20, 1}; 52 | titles[] = {0,""}; 53 | }; 54 | class AR_Rappel_End 55 | { 56 | name = "AR_Rappel_End"; 57 | sound[] = {"\AR_AdvancedRappelling\sounds\AR_Rappel_End.ogg", db+20, 1}; 58 | titles[] = {0,""}; 59 | }; 60 | }; 61 | 62 | #include "cfgAnimations.hpp" -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/functions/fn_advancedRappellingInit.sqf: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Seth Duda 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | */ 12 | 13 | if (!isServer) exitWith {}; 14 | 15 | AR_Advanced_Rappelling_Install = { 16 | 17 | // Prevent advanced rappelling from installing twice 18 | if(!isNil "AR_RAPPELLING_INIT") exitWith {}; 19 | AR_RAPPELLING_INIT = true; 20 | 21 | diag_log "Advanced Rappelling Loading..."; 22 | 23 | AP_RAPPEL_POINTS = []; 24 | 25 | AR_RAPPEL_POINT_CLASS_HEIGHT_OFFSET = [ 26 | ["All", [-0.05, -0.05, -0.05, -0.05, -0.05, -0.05]] 27 | ]; 28 | 29 | AR_Has_Addon_Animations_Installed = { 30 | (count getText ( configFile / "CfgMovesBasic" / "ManActions" / "AR_01" )) > 0; 31 | }; 32 | 33 | AR_Has_Addon_Sounds_Installed = { 34 | private ["_config","_configMission"]; 35 | _config = getArray ( configFile / "CfgSounds" / "AR_Rappel_Start" / "sound" ); 36 | _configMission = getArray ( missionConfigFile / "CfgSounds" / "AR_Rappel_Start" / "sound" ); 37 | (count _config > 0 || count _configMission > 0); 38 | }; 39 | 40 | AR_Rappel_All_Cargo = { 41 | params ["_vehicle",["_rappelHeight",25],["_positionASL",[]]]; 42 | if(isPlayer (driver _vehicle)) exitWith {}; 43 | if(local _vehicle) then { 44 | _this spawn { 45 | params ["_vehicle",["_rappelHeight",25],["_positionASL",[]]]; 46 | 47 | _heliGroup = group driver _vehicle; 48 | _vehicle setVariable ["AR_Units_Rappelling",true]; 49 | 50 | _heliGroupOriginalBehaviour = behaviour leader _heliGroup; 51 | _heliGroupOriginalCombatMode = combatMode leader _heliGroup; 52 | _heliGroupOriginalFormation = formation _heliGroup; 53 | 54 | if(count _positionASL == 0) then { 55 | _positionASL = AGLtoASL [(getPos _vehicle) select 0, (getPos _vehicle) select 1, 0]; 56 | }; 57 | _positionASL = _positionASL vectorAdd [0, 0, _rappelHeight]; 58 | 59 | _gameLogicLeader = _heliGroup createUnit ["LOGIC", ASLToAGL _positionASL, [], 0, ""]; 60 | _heliGroup selectLeader _gameLogicLeader; 61 | 62 | _heliGroup setBehaviour "Careless"; 63 | _heliGroup setCombatMode "Blue"; 64 | _heliGroup setFormation "File"; 65 | 66 | // Wait for heli to slow down 67 | waitUntil { (vectorMagnitude (velocity _vehicle)) < 10 && _vehicle distance2d _gameLogicLeader < 50 }; 68 | 69 | // Force heli to specific position 70 | [_vehicle, _positionASL] spawn { 71 | params ["_vehicle","_positionASL"]; 72 | 73 | while { _vehicle getVariable ["AR_Units_Rappelling",false] && alive driver _vehicle} do { 74 | 75 | _velocityMagatude = 5; 76 | _distanceToPosition = ((getPosASL _vehicle) distance _positionASL); 77 | if( _distanceToPosition <= 10 ) then { 78 | _velocityMagatude = (_distanceToPosition / 10) * _velocityMagatude; 79 | }; 80 | 81 | _currentVelocity = velocity _vehicle; 82 | _currentVelocity = _currentVelocity vectorAdd (( (getPosASL _vehicle) vectorFromTo _positionASL ) vectorMultiply _velocityMagatude); 83 | _currentVelocity = (vectorNormalized _currentVelocity) vectorMultiply ( (vectorMagnitude _currentVelocity) min _velocityMagatude ); 84 | _vehicle setVelocity _currentVelocity; 85 | 86 | sleep 0.05; 87 | }; 88 | }; 89 | 90 | // Find all units that will be rappelling 91 | _rappelUnits = []; 92 | _rappelledGroups = []; 93 | { 94 | if( group _x != _heliGroup && alive _x ) then { 95 | _rappelUnits pushBack _x; 96 | _rappelledGroups = _rappelledGroups + [group _x]; 97 | }; 98 | } forEach crew _vehicle; 99 | 100 | // Rappel all units 101 | _unitsOutsideVehicle = []; 102 | while { count _unitsOutsideVehicle != count _rappelUnits } do { 103 | _distanceToPosition = ((getPosASL _vehicle) distance _positionASL); 104 | if(_distanceToPosition < 3) then { 105 | { 106 | [_x, _vehicle] call AR_Rappel_From_Heli; 107 | sleep 1; 108 | } forEach (_rappelUnits-_unitsOutsideVehicle); 109 | { 110 | if!(_x in _vehicle) then { 111 | _unitsOutsideVehicle pushBack _x; 112 | }; 113 | } forEach (_rappelUnits-_unitsOutsideVehicle); 114 | }; 115 | sleep 2; 116 | }; 117 | 118 | // Wait for all units to reach ground 119 | _unitsRappelling = true; 120 | while { _unitsRappelling } do { 121 | _unitsRappelling = false; 122 | { 123 | if( _x getVariable ["AR_Is_Rappelling",false] ) then { 124 | _unitsRappelling = true; 125 | }; 126 | } forEach _rappelUnits; 127 | sleep 3; 128 | }; 129 | 130 | deleteVehicle _gameLogicLeader; 131 | 132 | _heliGroup setBehaviour _heliGroupOriginalBehaviour; 133 | _heliGroup setCombatMode _heliGroupOriginalCombatMode; 134 | _heliGroup setFormation _heliGroupOriginalFormation; 135 | 136 | _vehicle setVariable ["AR_Units_Rappelling",nil]; 137 | 138 | }; 139 | } else { 140 | [_this,"AR_Rappel_All_Cargo",_vehicle] call AR_RemoteExec; 141 | }; 142 | }; 143 | 144 | AR_Play_Rappelling_Sounds_Global = { 145 | _this remoteExec ["AR_Play_Rappelling_Sounds", 0]; 146 | }; 147 | 148 | AR_Play_Rappelling_Sounds = { 149 | params ["_player","_rappelDevice","_rappelAncor"]; 150 | if(!hasInterface || !(call AR_Has_Addon_Sounds_Installed) ) exitWith {}; 151 | if(player distance _player < 15) then { 152 | [_player, "AR_Rappel_Start"] call AR_Play_3D_Sound; 153 | [_rappelDevice, "AR_Rappel_Loop"] call AR_Play_3D_Sound; 154 | }; 155 | _this spawn { 156 | params ["_player","_rappelDevice","_rappelAncor"]; 157 | private ["_lastDistanceFromAnchor","_distanceFromAnchor"]; 158 | _lastDistanceFromAnchor = _rappelDevice distance _rappelAncor; 159 | while {_player getVariable ["AR_Is_Rappelling",false]} do { 160 | _distanceFromAnchor = _rappelDevice distance _rappelAncor; 161 | if(_distanceFromAnchor > _lastDistanceFromAnchor + 1 && player distance _player < 15) then { 162 | [_player, "AR_Rappel_Loop"] call AR_Play_3D_Sound; 163 | sleep 0.2; 164 | [_rappelDevice, "AR_Rappel_Loop"] call AR_Play_3D_Sound; 165 | }; 166 | sleep 0.9; 167 | _lastDistanceFromAnchor = _distanceFromAnchor; 168 | }; 169 | }; 170 | _this spawn { 171 | params ["_player"]; 172 | while {_player getVariable ["AR_Is_Rappelling",false]} do { 173 | sleep 0.1; 174 | }; 175 | if(player distance _player < 15) then { 176 | [_player, "AR_Rappel_End"] call AR_Play_3D_Sound; 177 | }; 178 | }; 179 | }; 180 | 181 | AR_Play_3D_Sound = { 182 | params ["_soundSource","_className"]; 183 | private ["_config","_configMission"]; 184 | _config = getArray ( configFile / "CfgSounds" / _className / "sound" ); 185 | if(count _config > 0) exitWith { 186 | _soundSource say3D _className; 187 | }; 188 | _configMission = getArray ( missionConfigFile / "CfgSounds" / _className / "sound" ); 189 | if(count _configMission > 0) exitWith { 190 | _soundSource say3D _className; 191 | }; 192 | }; 193 | 194 | AR_Get_Heli_Rappel_Points = { 195 | params ["_vehicle"]; 196 | 197 | // Check for pre-defined rappel points 198 | 199 | private ["_preDefinedRappelPoints","_className","_rappelPoints","_preDefinedRappelPointsConverted"]; 200 | _preDefinedRappelPoints = []; 201 | { 202 | _className = _x select 0; 203 | _rappelPoints = _x select 1; 204 | if( _vehicle isKindOf _className ) then { 205 | _preDefinedRappelPoints = _rappelPoints; 206 | }; 207 | } forEach (AP_RAPPEL_POINTS + (missionNamespace getVariable ["AP_CUSTOM_RAPPEL_POINTS",[]])); 208 | if(count _preDefinedRappelPoints > 0) exitWith { 209 | _preDefinedRappelPointsConverted = []; 210 | { 211 | if(typeName _x == "STRING") then { 212 | _modelPosition = _vehicle selectionPosition _x; 213 | if( [0,0,0] distance _modelPosition > 0 ) then { 214 | _preDefinedRappelPointsConverted pushBack _modelPosition; 215 | }; 216 | } else { 217 | _preDefinedRappelPointsConverted pushBack _x; 218 | }; 219 | } forEach _preDefinedRappelPoints; 220 | _preDefinedRappelPointsConverted; 221 | }; 222 | 223 | // Calculate dynamic rappel points 224 | 225 | private ["_rappelPointsArray","_cornerPoints","_frontLeftPoint","_frontRightPoint","_rearLeftPoint","_rearRightPoint","_rearLeftPointFinal"]; 226 | private ["_rearRightPointFinal","_frontLeftPointFinal","_frontRightPointFinal","_middleLeftPointFinal","_middleRightPointFinal","_vehicleUnitVectorUp"]; 227 | private ["_rappelPoints","_modelPoint","_modelPointASL","_surfaceIntersectStartASL","_surfaceIntersectEndASL","_surfaces","_intersectionASL","_intersectionObject"]; 228 | private ["_la","_lb","_n","_p0","_l","_d","_validRappelPoints"]; 229 | 230 | _rappelPointsArray = []; 231 | _cornerPoints = [_vehicle] call AR_Get_Corner_Points; 232 | 233 | _frontLeftPoint = (((_cornerPoints select 2) vectorDiff (_cornerPoints select 3)) vectorMultiply 0.2) vectorAdd (_cornerPoints select 3); 234 | _frontRightPoint = (((_cornerPoints select 2) vectorDiff (_cornerPoints select 3)) vectorMultiply 0.8) vectorAdd (_cornerPoints select 3); 235 | _rearLeftPoint = (((_cornerPoints select 0) vectorDiff (_cornerPoints select 1)) vectorMultiply 0.2) vectorAdd (_cornerPoints select 1); 236 | _rearRightPoint = (((_cornerPoints select 0) vectorDiff (_cornerPoints select 1)) vectorMultiply 0.8) vectorAdd (_cornerPoints select 1); 237 | 238 | _rearLeftPointFinal = ((_frontLeftPoint vectorDiff _rearLeftPoint) vectorMultiply 0.2) vectorAdd _rearLeftPoint; 239 | _rearRightPointFinal = ((_frontRightPoint vectorDiff _rearRightPoint) vectorMultiply 0.2) vectorAdd _rearRightPoint; 240 | _frontLeftPointFinal = ((_rearLeftPoint vectorDiff _frontLeftPoint) vectorMultiply 0.2) vectorAdd _frontLeftPoint; 241 | _frontRightPointFinal = ((_rearRightPoint vectorDiff _frontRightPoint) vectorMultiply 0.2) vectorAdd _frontRightPoint; 242 | _middleLeftPointFinal = ((_frontLeftPointFinal vectorDiff _rearLeftPointFinal) vectorMultiply 0.5) vectorAdd _rearLeftPointFinal; 243 | _middleRightPointFinal = ((_frontRightPointFinal vectorDiff _rearRightPointFinal) vectorMultiply 0.5) vectorAdd _rearRightPointFinal; 244 | 245 | _vehicleUnitVectorUp = vectorNormalized (vectorUp _vehicle); 246 | 247 | _rappelPointHeightOffset = 0; 248 | { 249 | if(_vehicle isKindOf (_x select 0)) then { 250 | _rappelPointHeightOffset = (_x select 1); 251 | }; 252 | } forEach AR_RAPPEL_POINT_CLASS_HEIGHT_OFFSET; 253 | 254 | _rappelPoints = []; 255 | { 256 | _modelPoint = _x; 257 | _modelPointASL = AGLToASL (_vehicle modelToWorldVisual _modelPoint); 258 | _surfaceIntersectStartASL = _modelPointASL vectorAdd ( _vehicleUnitVectorUp vectorMultiply -5 ); 259 | _surfaceIntersectEndASL = _modelPointASL vectorAdd ( _vehicleUnitVectorUp vectorMultiply 5 ); 260 | 261 | // Determine if the surface intersection line crosses below ground level 262 | // If if does, move surfaceIntersectStartASL above ground level (lineIntersectsSurfaces 263 | // doesn't work if starting below ground level for some reason 264 | // See: https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection 265 | 266 | _la = ASLToAGL _surfaceIntersectStartASL; 267 | _lb = ASLToAGL _surfaceIntersectEndASL; 268 | 269 | if(_la select 2 < 0 && _lb select 2 > 0) then { 270 | _n = [0,0,1]; 271 | _p0 = [0,0,0.1]; 272 | _l = (_la vectorFromTo _lb); 273 | if((_l vectorDotProduct _n) != 0) then { 274 | _d = ( ( _p0 vectorAdd ( _la vectorMultiply -1 ) ) vectorDotProduct _n ) / (_l vectorDotProduct _n); 275 | _surfaceIntersectStartASL = AGLToASL ((_l vectorMultiply _d) vectorAdd _la); 276 | }; 277 | }; 278 | 279 | _surfaces = lineIntersectsSurfaces [_surfaceIntersectStartASL, _surfaceIntersectEndASL, objNull, objNull, true, 100]; 280 | _intersectionASL = []; 281 | { 282 | _intersectionObject = _x select 2; 283 | if(_intersectionObject == _vehicle) exitWith { 284 | _intersectionASL = _x select 0; 285 | }; 286 | } forEach _surfaces; 287 | if(count _intersectionASL > 0) then { 288 | _intersectionASL = _intersectionASL vectorAdd (( _surfaceIntersectStartASL vectorFromTo _surfaceIntersectEndASL ) vectorMultiply (_rappelPointHeightOffset select (count _rappelPoints))); 289 | _rappelPoints pushBack (_vehicle worldToModelVisual (ASLToAGL _intersectionASL)); 290 | } else { 291 | _rappelPoints pushBack []; 292 | }; 293 | } forEach [_middleLeftPointFinal, _middleRightPointFinal, _frontLeftPointFinal, _frontRightPointFinal, _rearLeftPointFinal, _rearRightPointFinal]; 294 | 295 | _validRappelPoints = []; 296 | { 297 | if(count _x > 0 && count _validRappelPoints < missionNamespace getVariable ["AR_MAX_RAPPEL_POINTS_OVERRIDE",6]) then { 298 | _validRappelPoints pushBack _x; 299 | }; 300 | } forEach _rappelPoints; 301 | 302 | _validRappelPoints; 303 | }; 304 | 305 | 306 | AR_Rappel_From_Heli = { 307 | params ["_player","_heli"]; 308 | if(isServer) then { 309 | 310 | if!(_player in _heli) exitWith {}; 311 | if(_player getVariable ["AR_Is_Rappelling", false]) exitWith {}; 312 | 313 | // Find next available rappel anchor 314 | _rappelPoints = [_heli] call AR_Get_Heli_Rappel_Points; 315 | _rappelPointIndex = 0; 316 | { 317 | _rappellingPlayer = _heli getVariable ["AR_Rappelling_Player_" + str _rappelPointIndex,objNull]; 318 | if(isNull _rappellingPlayer) exitWith {}; 319 | _rappelPointIndex = _rappelPointIndex + 1; 320 | } forEach _rappelPoints; 321 | 322 | // All rappel anchors are taken by other players. Hint player to try again. 323 | if(count _rappelPoints == _rappelPointIndex) exitWith { 324 | if(isPlayer _player) then { 325 | [["All rappel anchors in use. Please try again.", false],"AR_Hint",_player] call AR_RemoteExec; 326 | }; 327 | }; 328 | 329 | _heli setVariable ["AR_Rappelling_Player_" + str _rappelPointIndex,_player]; 330 | 331 | _player setVariable ["AR_Is_Rappelling",true,true]; 332 | 333 | // Start rappelling (client side) 334 | [_player,_heli,_rappelPoints select _rappelPointIndex] spawn AR_Client_Rappel_From_Heli; 335 | 336 | // Wait for player to finish rappeling before freeing up anchor 337 | [_player, _heli, _rappelPointIndex] spawn { 338 | params ["_player","_heli", "_rappelPointIndex"]; 339 | while {true} do { 340 | if(!alive _player) exitWith {}; 341 | if!(_player getVariable ["AR_Is_Rappelling", false]) exitWith {}; 342 | sleep 2; 343 | }; 344 | _heli setVariable ["AR_Rappelling_Player_" + str _rappelPointIndex, nil]; 345 | }; 346 | 347 | } else { 348 | [_this,"AR_Rappel_From_Heli",true] call AR_RemoteExecServer; 349 | }; 350 | }; 351 | 352 | AR_Client_Rappel_From_Heli = { 353 | params ["_player","_heli","_rappelPoint"]; 354 | if(local _player) then { 355 | [_player] orderGetIn false; 356 | moveOut _player; 357 | waitUntil { vehicle _player == _player}; 358 | _playerStartPosition = AGLtoASL (_heli modelToWorldVisual _rappelPoint); 359 | _playerStartPosition set [2,(_playerStartPosition select 2) - 1]; 360 | _playerStartPosition set [1,(_playerStartPosition select 1) - ((((random 100)-50))/25)]; 361 | _playerStartPosition set [0,(_playerStartPosition select 0) - ((((random 100)-50))/25)]; 362 | _player setPosWorld _playerStartPosition; 363 | 364 | _anchor = "Land_Can_V2_F" createVehicle position _player; 365 | _anchor allowDamage false; 366 | hideObject _anchor; 367 | [[_anchor],"AR_Hide_Object_Global"] call AR_RemoteExecServer; 368 | _anchor attachTo [_heli,_rappelPoint]; 369 | 370 | _rappelDevice = "B_static_AA_F" createVehicle position _player; 371 | _rappelDevice setPosWorld _playerStartPosition; 372 | _rappelDevice allowDamage false; 373 | hideObject _rappelDevice; 374 | [[_rappelDevice],"AR_Hide_Object_Global"] call AR_RemoteExecServer; 375 | 376 | [[_player,_rappelDevice,_anchor],"AR_Play_Rappelling_Sounds_Global"] call AR_RemoteExecServer; 377 | 378 | _bottomRopeLength = 60; 379 | _bottomRope = ropeCreate [_rappelDevice, [-0.15,0,0], _bottomRopeLength]; 380 | _bottomRope allowDamage false; 381 | _topRopeLength = 3; 382 | _topRope = ropeCreate [_rappelDevice, [0,0.15,0], _anchor, [0, 0, 0], _topRopeLength]; 383 | _topRope allowDamage false; 384 | 385 | [_player] spawn AR_Enable_Rappelling_Animation_Client; 386 | 387 | _gravityAccelerationVec = [0,0,-9.8]; 388 | _velocityVec = [0,0,0]; 389 | _lastTime = diag_tickTime; 390 | _lastPosition = AGLtoASL (_rappelDevice modelToWorldVisual [0,0,0]); 391 | _lookDirFreedom = 50; 392 | _dir = (random 360) + (_lookDirFreedom / 2); 393 | _dirSpinFactor = (((random 10) - 5) / 5) max 0.1; 394 | 395 | _ropeKeyDownHandler = -1; 396 | _ropeKeyUpHandler = -1; 397 | if(_player == player) then { 398 | 399 | _player setVariable ["AR_DECEND_PRESSED",false]; 400 | _player setVariable ["AR_FAST_DECEND_PRESSED",false]; 401 | _player setVariable ["AR_RANDOM_DECEND_SPEED_ADJUSTMENT",0]; 402 | 403 | _ropeKeyDownHandler = (findDisplay 46) displayAddEventHandler ["KeyDown", { 404 | if(_this select 1 in (actionKeys "MoveBack")) then { 405 | player setVariable ["AR_DECEND_PRESSED",true]; 406 | }; 407 | if(_this select 1 in (actionKeys "Turbo")) then { 408 | player setVariable ["AR_FAST_DECEND_PRESSED",true]; 409 | }; 410 | }]; 411 | 412 | _ropeKeyUpHandler = (findDisplay 46) displayAddEventHandler ["KeyUp", { 413 | if(_this select 1 in (actionKeys "MoveBack")) then { 414 | player setVariable ["AR_DECEND_PRESSED",false]; 415 | }; 416 | if(_this select 1 in (actionKeys "Turbo")) then { 417 | player setVariable ["AR_FAST_DECEND_PRESSED",false]; 418 | }; 419 | }]; 420 | 421 | } else { 422 | 423 | _player setVariable ["AR_DECEND_PRESSED",false]; 424 | _player setVariable ["AR_FAST_DECEND_PRESSED",false]; 425 | _player setVariable ["AR_RANDOM_DECEND_SPEED_ADJUSTMENT",(random 2) - 1]; 426 | 427 | [_player] spawn { 428 | params ["_player"]; 429 | sleep 2; 430 | _player setVariable ["AR_DECEND_PRESSED",true]; 431 | }; 432 | 433 | }; 434 | 435 | // Cause player to fall from rope if heli is moving too fast 436 | _this spawn { 437 | params ["_player","_heli"]; 438 | while {_player getVariable ["AR_Is_Rappelling", false]} do { 439 | if(speed _heli > 150) then { 440 | if(isPlayer _player) then { 441 | ["Moving too fast! You've lost grip of the rope.", false] call AR_Hint; 442 | }; 443 | [_player] call AR_Rappel_Detach_Action; 444 | }; 445 | sleep 2; 446 | }; 447 | }; 448 | 449 | 450 | 451 | while {true} do { 452 | 453 | _currentTime = diag_tickTime; 454 | _timeSinceLastUpdate = _currentTime - _lastTime; 455 | _lastTime = _currentTime; 456 | if(_timeSinceLastUpdate > 1) then { 457 | _timeSinceLastUpdate = 0; 458 | }; 459 | 460 | _environmentWindVelocity = wind; 461 | _playerWindVelocity = _velocityVec vectorMultiply -1; 462 | _helicopterWindVelocity = (vectorUp _heli) vectorMultiply -30; 463 | _totalWindVelocity = _environmentWindVelocity vectorAdd _playerWindVelocity vectorAdd _helicopterWindVelocity; 464 | _totalWindForce = _totalWindVelocity vectorMultiply (9.8/53); 465 | 466 | _accelerationVec = _gravityAccelerationVec vectorAdd _totalWindForce; 467 | _velocityVec = _velocityVec vectorAdd ( _accelerationVec vectorMultiply _timeSinceLastUpdate ); 468 | _newPosition = _lastPosition vectorAdd ( _velocityVec vectorMultiply _timeSinceLastUpdate ); 469 | 470 | _heliPos = AGLtoASL (_heli modelToWorldVisual _rappelPoint); 471 | 472 | if(_newPosition distance _heliPos > _topRopeLength) then { 473 | _newPosition = (_heliPos) vectorAdd (( vectorNormalized ( (_heliPos) vectorFromTo _newPosition )) vectorMultiply _topRopeLength); 474 | _surfaceVector = ( vectorNormalized ( _newPosition vectorFromTo (_heliPos) )); 475 | _velocityVec = _velocityVec vectorAdd (( _surfaceVector vectorMultiply (_velocityVec vectorDotProduct _surfaceVector)) vectorMultiply -1); 476 | }; 477 | 478 | _rappelDevice setPosWorld (_lastPosition vectorAdd ((_newPosition vectorDiff _lastPosition) vectorMultiply 6)); 479 | 480 | _rappelDevice setVectorDir (vectorDir _player); 481 | _player setPosWorld [_newPosition select 0, _newPosition select 1, (_newPosition select 2)-0.6]; 482 | _player setVelocity [0,0,0]; 483 | 484 | // Handle rappelling down rope 485 | if(_player getVariable ["AR_DECEND_PRESSED",false]) then { 486 | _decendSpeedMetersPerSecond = 3.5; 487 | if(_player getVariable ["AR_FAST_DECEND_PRESSED",false]) then { 488 | _decendSpeedMetersPerSecond = 5; 489 | }; 490 | _decendSpeedMetersPerSecond = _decendSpeedMetersPerSecond + (_player getVariable ["AR_RANDOM_DECEND_SPEED_ADJUSTMENT",0]); 491 | _bottomRopeLength = _bottomRopeLength - (_timeSinceLastUpdate * _decendSpeedMetersPerSecond); 492 | _topRopeLength = _topRopeLength + (_timeSinceLastUpdate * _decendSpeedMetersPerSecond); 493 | ropeUnwind [_topRope, _decendSpeedMetersPerSecond, _topRopeLength - 0.5]; 494 | ropeUnwind [_bottomRope, _decendSpeedMetersPerSecond, _bottomRopeLength]; 495 | }; 496 | 497 | // Fix player direction 498 | _dir = _dir + ((360/1000) * _dirSpinFactor); 499 | if(isPlayer _player) then { 500 | _currentDir = getDir _player; 501 | _minDir = (_dir - (_lookDirFreedom/2)) mod 360; 502 | _maxDir = (_dir + (_lookDirFreedom/2)) mod 360; 503 | _minDegreesToMax = 0; 504 | _minDegreesToMin = 0; 505 | if( _currentDir > _maxDir ) then { 506 | _minDegreesToMax = (_currentDir - _maxDir) min (360 - _currentDir + _maxDir); 507 | }; 508 | if( _currentDir < _maxDir ) then { 509 | _minDegreesToMax = (_maxDir - _currentDir) min (360 - _maxDir + _currentDir); 510 | }; 511 | if( _currentDir > _minDir ) then { 512 | _minDegreesToMin = (_currentDir - _minDir) min (360 - _currentDir + _minDir); 513 | }; 514 | if( _currentDir < _minDir ) then { 515 | _minDegreesToMin = (_minDir - _currentDir) min (360 - _minDir + _currentDir); 516 | }; 517 | if( _minDegreesToMin > _lookDirFreedom || _minDegreesToMax > _lookDirFreedom ) then { 518 | if( _minDegreesToMin < _minDegreesToMax ) then { 519 | _player setDir _minDir; 520 | } else { 521 | _player setDir _maxDir; 522 | }; 523 | } else { 524 | _player setDir (_currentDir + ((360/1000) * _dirSpinFactor)); 525 | }; 526 | } else { 527 | _player setDir _dir; 528 | }; 529 | 530 | _lastPosition = _newPosition; 531 | 532 | if((getPos _player) select 2 < 1 || !alive _player || vehicle _player != _player || _bottomRopeLength <= 1 || _player getVariable ["AR_Detach_Rope",false] ) exitWith {}; 533 | 534 | sleep 0.01; 535 | }; 536 | 537 | if(_bottomRopeLength > 1 && alive _player && vehicle _player == _player) then { 538 | 539 | _playerStartASLIntersect = getPosASL _player; 540 | _playerEndASLIntersect = [_playerStartASLIntersect select 0, _playerStartASLIntersect select 1, (_playerStartASLIntersect select 2) - 5]; 541 | _surfaces = lineIntersectsSurfaces [_playerStartASLIntersect, _playerEndASLIntersect, _player, objNull, true, 10]; 542 | _intersectionASL = []; 543 | { 544 | scopeName "surfaceLoop"; 545 | _intersectionObject = _x select 2; 546 | _objectFileName = str _intersectionObject; 547 | if((_objectFileName find " t_") == -1 && (_objectFileName find " b_") == -1) then { 548 | _intersectionASL = _x select 0; 549 | breakOut "surfaceLoop"; 550 | }; 551 | } forEach _surfaces; 552 | 553 | if(count _intersectionASL != 0) then { 554 | _player allowDamage false; 555 | _player setPosASL _intersectionASL; 556 | }; 557 | 558 | if(_player getVariable ["AR_Detach_Rope",false]) then { 559 | // Player detached from rope. Don't prevent damage 560 | // if we didn't find a position on the ground 561 | if(count _intersectionASL == 0) then { 562 | _player allowDamage true; 563 | }; 564 | }; 565 | 566 | // Allow damage if you get out of a heli with no engine on 567 | if(!isEngineOn _heli) then { 568 | _player allowDamage true; 569 | }; 570 | 571 | }; 572 | 573 | ropeDestroy _topRope; 574 | ropeDestroy _bottomRope; 575 | deleteVehicle _anchor; 576 | deleteVehicle _rappelDevice; 577 | 578 | _player setVariable ["AR_Is_Rappelling",nil,true]; 579 | _player setVariable ["AR_Rappelling_Vehicle", nil, true]; 580 | _player setVariable ["AR_Detach_Rope",nil]; 581 | 582 | if(_ropeKeyDownHandler != -1) then { 583 | (findDisplay 46) displayRemoveEventHandler ["KeyDown", _ropeKeyDownHandler]; 584 | }; 585 | 586 | if(_ropeKeyUpHandler != -1) then { 587 | (findDisplay 46) displayRemoveEventHandler ["KeyUp", _ropeKeyUpHandler]; 588 | }; 589 | 590 | sleep 2; 591 | 592 | _player allowDamage true; 593 | 594 | } else { 595 | [_this,"AR_Client_Rappel_From_Heli",_player] call AR_RemoteExec; 596 | }; 597 | }; 598 | 599 | 600 | AR_Enable_Rappelling_Animation = { 601 | params ["_player"]; 602 | [_player,true] remoteExec ["AR_Enable_Rappelling_Animation_Client", 0]; 603 | }; 604 | 605 | AR_Current_Weapon_Type_Selected = { 606 | params ["_player"]; 607 | if(currentWeapon _player == handgunWeapon _player) exitWith {"HANDGUN"}; 608 | if(currentWeapon _player == primaryWeapon _player) exitWith {"PRIMARY"}; 609 | if(currentWeapon _player == secondaryWeapon _player) exitWith {"SECONDARY"}; 610 | "OTHER"; 611 | }; 612 | 613 | AR_Enable_Rappelling_Animation_Client = { 614 | params ["_player",["_globalExec",false]]; 615 | 616 | if(local _player && _globalExec) exitWith {}; 617 | 618 | if(local _player && !_globalExec) then { 619 | [[_player],"AR_Enable_Rappelling_Animation"] call AR_RemoteExecServer; 620 | }; 621 | 622 | if(_player != player) then { 623 | _player enableSimulation false; 624 | }; 625 | 626 | if(call AR_Has_Addon_Animations_Installed) then { 627 | if([_player] call AR_Current_Weapon_Type_Selected == "HANDGUN") then { 628 | if(local _player) then { 629 | if(missionNamespace getVariable ["AR_DISABLE_SHOOTING_OVERRIDE",false]) then { 630 | _player switchMove "AR_01_Idle_Pistol_No_Actions"; 631 | } else { 632 | _player switchMove "AR_01_Idle_Pistol"; 633 | }; 634 | _player setVariable ["AR_Animation_Move","AR_01_Idle_Pistol_No_Actions",true]; 635 | } else { 636 | _player setVariable ["AR_Animation_Move","AR_01_Idle_Pistol_No_Actions"]; 637 | }; 638 | } else { 639 | if(local _player) then { 640 | if(missionNamespace getVariable ["AR_DISABLE_SHOOTING_OVERRIDE",false]) then { 641 | _player switchMove "AR_01_Idle_No_Actions"; 642 | } else { 643 | _player switchMove "AR_01_Idle"; 644 | }; 645 | _player setVariable ["AR_Animation_Move","AR_01_Idle_No_Actions",true]; 646 | } else { 647 | _player setVariable ["AR_Animation_Move","AR_01_Idle_No_Actions"]; 648 | }; 649 | }; 650 | if!(local _player) then { 651 | // Temp work around to avoid seeing other player as standing 652 | _player switchMove (_player getVariable ["AR_Animation_Move","HubSittingChairC_idle1"]); 653 | sleep 1; 654 | _player switchMove (_player getVariable ["AR_Animation_Move","HubSittingChairC_idle1"]); 655 | sleep 1; 656 | _player switchMove (_player getVariable ["AR_Animation_Move","HubSittingChairC_idle1"]); 657 | sleep 1; 658 | _player switchMove (_player getVariable ["AR_Animation_Move","HubSittingChairC_idle1"]); 659 | }; 660 | } else { 661 | if(local _player) then { 662 | _player switchMove "HubSittingChairC_idle1"; 663 | _player setVariable ["AR_Animation_Move","HubSittingChairC_idle1",true]; 664 | } else { 665 | _player setVariable ["AR_Animation_Move","HubSittingChairC_idle1"]; 666 | }; 667 | }; 668 | 669 | _animationEventHandler = -1; 670 | if(local _player) then { 671 | _animationEventHandler = _player addEventHandler ["AnimChanged",{ 672 | params ["_player","_animation"]; 673 | if(call AR_Has_Addon_Animations_Installed) then { 674 | if((toLower _animation) find "ar_" < 0) then { 675 | if([_player] call AR_Current_Weapon_Type_Selected == "HANDGUN") then { 676 | _player switchMove "AR_01_Aim_Pistol"; 677 | _player setVariable ["AR_Animation_Move","AR_01_Aim_Pistol_No_Actions",true]; 678 | } else { 679 | _player switchMove "AR_01_Aim"; 680 | _player setVariable ["AR_Animation_Move","AR_01_Aim_No_Actions",true]; 681 | }; 682 | } else { 683 | if(toLower _animation == "ar_01_aim") then { 684 | _player setVariable ["AR_Animation_Move","AR_01_Aim_No_Actions",true]; 685 | }; 686 | if(toLower _animation == "ar_01_idle") then { 687 | _player setVariable ["AR_Animation_Move","AR_01_Idle_No_Actions",true]; 688 | }; 689 | if(toLower _animation == "ar_01_aim_pistol") then { 690 | _player setVariable ["AR_Animation_Move","AR_01_Aim_Pistol_No_Actions",true]; 691 | }; 692 | if(toLower _animation == "ar_01_idle_pistol") then { 693 | _player setVariable ["AR_Animation_Move","AR_01_Idle_Pistol_No_Actions",true]; 694 | }; 695 | }; 696 | } else { 697 | _player switchMove "HubSittingChairC_idle1"; 698 | _player setVariable ["AR_Animation_Move","HubSittingChairC_idle1",true]; 699 | }; 700 | }]; 701 | }; 702 | 703 | if(!local _player) then { 704 | [_player] spawn { 705 | params ["_player"]; 706 | private ["_currentState"]; 707 | while {_player getVariable ["AR_Is_Rappelling",false]} do { 708 | _currentState = toLower animationState _player; 709 | _newState = toLower (_player getVariable ["AR_Animation_Move",""]); 710 | if!(call AR_Has_Addon_Animations_Installed) then { 711 | _newState = "HubSittingChairC_idle1"; 712 | }; 713 | if(_currentState != _newState) then { 714 | _player switchMove _newState; 715 | _player switchGesture ""; 716 | sleep 1; 717 | _player switchMove _newState; 718 | _player switchGesture ""; 719 | }; 720 | sleep 0.1; 721 | }; 722 | }; 723 | }; 724 | 725 | waitUntil {!(_player getVariable ["AR_Is_Rappelling",false])}; 726 | 727 | if(_animationEventHandler != -1) then { 728 | _player removeEventHandler ["AnimChanged", _animationEventHandler]; 729 | }; 730 | 731 | _player switchMove ""; 732 | _player enableSimulation true; 733 | 734 | }; 735 | 736 | AR_Rappel_Detach_Action = { 737 | params ["_player"]; 738 | _player setVariable ["AR_Detach_Rope",true]; 739 | }; 740 | 741 | AR_Rappel_Detach_Action_Check = { 742 | params ["_player"]; 743 | if!(_player getVariable ["AR_Is_Rappelling",false]) exitWith {false;}; 744 | true; 745 | }; 746 | 747 | AR_Rappel_From_Heli_Action = { 748 | params ["_player","_vehicle"]; 749 | if([_player, _vehicle] call AR_Rappel_From_Heli_Action_Check) then { 750 | [_player, _vehicle] call AR_Rappel_From_Heli; 751 | }; 752 | }; 753 | 754 | AR_Rappel_From_Heli_Action_Check = { 755 | params ["_player","_vehicle"]; 756 | if!([_vehicle] call AR_Is_Supported_Vehicle) exitWith {false}; 757 | if(((getPos _vehicle) select 2) < 5 ) exitWith {false}; 758 | if(((getPos _vehicle) select 2) > 150 ) exitWith {false}; 759 | if(driver _vehicle == _player && isEngineOn _vehicle) exitWith {false}; 760 | if(speed _vehicle > 100) exitWith {false}; 761 | true; 762 | }; 763 | 764 | AR_Rappel_AI_Units_From_Heli_Action_Check = { 765 | params ["_player"]; 766 | if(leader _player != _player) exitWith {false}; 767 | _canRappelOne = false; 768 | { 769 | if(vehicle _x != _x && !isPlayer _x) then { 770 | if([_x, vehicle _x] call AR_Rappel_From_Heli_Action_Check) then { 771 | _canRappelOne = true; 772 | }; 773 | }; 774 | } forEach (units _player); 775 | _canRappelOne; 776 | }; 777 | 778 | AR_Get_Corner_Points = { 779 | params ["_vehicle"]; 780 | private ["_centerOfMass","_bbr","_p1","_p2","_rearCorner","_rearCorner2","_frontCorner","_frontCorner2"]; 781 | private ["_maxWidth","_widthOffset","_maxLength","_lengthOffset","_widthFactor","_lengthFactor","_maxHeight","_heightOffset"]; 782 | 783 | // Correct width and length factor for air 784 | _widthFactor = 0.5; 785 | _lengthFactor = 0.5; 786 | if(_vehicle isKindOf "Air") then { 787 | _widthFactor = 0.3; 788 | }; 789 | if(_vehicle isKindOf "Helicopter") then { 790 | _widthFactor = 0.2; 791 | _lengthFactor = 0.45; 792 | }; 793 | 794 | _centerOfMass = getCenterOfMass _vehicle; 795 | _bbr = boundingBoxReal _vehicle; 796 | _p1 = _bbr select 0; 797 | _p2 = _bbr select 1; 798 | _maxWidth = abs ((_p2 select 0) - (_p1 select 0)); 799 | _widthOffset = ((_maxWidth / 2) - abs ( _centerOfMass select 0 )) * _widthFactor; 800 | _maxLength = abs ((_p2 select 1) - (_p1 select 1)); 801 | _lengthOffset = ((_maxLength / 2) - abs (_centerOfMass select 1 )) * _lengthFactor; 802 | _maxHeight = abs ((_p2 select 2) - (_p1 select 2)); 803 | _heightOffset = _maxHeight/6; 804 | 805 | _rearCorner = [(_centerOfMass select 0) + _widthOffset, (_centerOfMass select 1) - _lengthOffset, (_centerOfMass select 2)+_heightOffset]; 806 | _rearCorner2 = [(_centerOfMass select 0) - _widthOffset, (_centerOfMass select 1) - _lengthOffset, (_centerOfMass select 2)+_heightOffset]; 807 | _frontCorner = [(_centerOfMass select 0) + _widthOffset, (_centerOfMass select 1) + _lengthOffset, (_centerOfMass select 2)+_heightOffset]; 808 | _frontCorner2 = [(_centerOfMass select 0) - _widthOffset, (_centerOfMass select 1) + _lengthOffset, (_centerOfMass select 2)+_heightOffset]; 809 | 810 | [_rearCorner,_rearCorner2,_frontCorner,_frontCorner2]; 811 | }; 812 | 813 | AR_SUPPORTED_VEHICLES = [ 814 | "Helicopter", 815 | "VTOL_Base_F" 816 | ]; 817 | 818 | AR_Is_Supported_Vehicle = { 819 | params ["_vehicle","_isSupported"]; 820 | _isSupported = false; 821 | if(not isNull _vehicle) then { 822 | { 823 | if(_vehicle isKindOf _x) then { 824 | _isSupported = true; 825 | }; 826 | } forEach (missionNamespace getVariable ["AR_SUPPORTED_VEHICLES_OVERRIDE",AR_SUPPORTED_VEHICLES]); 827 | }; 828 | _isSupported; 829 | }; 830 | 831 | AR_Hint = { 832 | params ["_msg",["_isSuccess",true]]; 833 | if(!isNil "ExileClient_gui_notification_event_addNotification") then { 834 | if(_isSuccess) then { 835 | ["Success", [_msg]] call ExileClient_gui_notification_event_addNotification; 836 | } else { 837 | ["Whoops", [_msg]] call ExileClient_gui_notification_event_addNotification; 838 | }; 839 | } else { 840 | hint _msg; 841 | }; 842 | }; 843 | 844 | AR_Hide_Object_Global = { 845 | params ["_obj"]; 846 | if( _obj isKindOf "Land_Can_V2_F" || _obj isKindOf "B_static_AA_F" ) then { 847 | hideObjectGlobal _obj; 848 | }; 849 | }; 850 | 851 | AR_Add_Player_Actions = { 852 | params ["_player"]; 853 | 854 | _player addAction ["Rappel Self", { 855 | [player, vehicle player] call AR_Rappel_From_Heli_Action; 856 | }, nil, 0, false, true, "", "[player, vehicle player] call AR_Rappel_From_Heli_Action_Check"]; 857 | 858 | _player addAction ["Rappel AI Units", { 859 | { 860 | if(!isPlayer _x) then { 861 | sleep 1; 862 | [_x, vehicle _x] call AR_Rappel_From_Heli_Action; 863 | }; 864 | } forEach (units player); 865 | }, nil, 0, false, true, "", "[player] call AR_Rappel_AI_Units_From_Heli_Action_Check"]; 866 | 867 | _player addAction ["Detach Rappel Device", { 868 | [player] call AR_Rappel_Detach_Action; 869 | }, nil, 0, false, true, "", "[player] call AR_Rappel_Detach_Action_Check"]; 870 | 871 | _player addEventHandler ["Respawn", { 872 | player setVariable ["AR_Actions_Loaded",false]; 873 | }]; 874 | 875 | }; 876 | 877 | if(!isDedicated) then { 878 | [] spawn { 879 | while {true} do { 880 | if(!isNull player && isPlayer player) then { 881 | if!(player getVariable ["AR_Actions_Loaded",false] ) then { 882 | [player] call AR_Add_Player_Actions; 883 | player setVariable ["AR_Actions_Loaded",true]; 884 | }; 885 | }; 886 | sleep 5; 887 | }; 888 | }; 889 | }; 890 | 891 | AR_RemoteExec = { 892 | params ["_params","_functionName","_target",["_isCall",false]]; 893 | if(!isNil "ExileClient_system_network_send") then { 894 | ["AdvancedRappellingRemoteExecClient",[_params,_functionName,_target,_isCall]] call ExileClient_system_network_send; 895 | } else { 896 | if(_isCall) then { 897 | _params remoteExecCall [_functionName, _target]; 898 | } else { 899 | _params remoteExec [_functionName, _target]; 900 | }; 901 | }; 902 | }; 903 | 904 | AR_RemoteExecServer = { 905 | params ["_params","_functionName",["_isCall",false]]; 906 | if(!isNil "ExileClient_system_network_send") then { 907 | ["AdvancedRappellingRemoteExecServer",[_params,_functionName,_isCall]] call ExileClient_system_network_send; 908 | } else { 909 | if(_isCall) then { 910 | _params remoteExecCall [_functionName, 2]; 911 | } else { 912 | _params remoteExec [_functionName, 2]; 913 | }; 914 | }; 915 | }; 916 | 917 | if(isServer) then { 918 | 919 | // Adds support for exile network calls (Only used when running exile) // 920 | 921 | AR_SUPPORTED_REMOTEEXECSERVER_FUNCTIONS = ["AR_Hide_Object_Global","AR_Enable_Rappelling_Animation","AR_Rappel_From_Heli","AR_Play_Rappelling_Sounds_Global"]; 922 | 923 | ExileServer_AdvancedRappelling_network_AdvancedRappellingRemoteExecServer = { 924 | params ["_sessionId", "_messageParameters",["_isCall",false]]; 925 | _messageParameters params ["_params","_functionName"]; 926 | if(_functionName in AR_SUPPORTED_REMOTEEXECSERVER_FUNCTIONS) then { 927 | if(_isCall) then { 928 | _params call (missionNamespace getVariable [_functionName,{}]); 929 | } else { 930 | _params spawn (missionNamespace getVariable [_functionName,{}]); 931 | }; 932 | }; 933 | }; 934 | 935 | AR_SUPPORTED_REMOTEEXECCLIENT_FUNCTIONS = ["AR_Client_Rappel_From_Heli","AR_Hint","AR_Rappel_All_Cargo"]; 936 | 937 | ExileServer_AdvancedRappelling_network_AdvancedRappellingRemoteExecClient = { 938 | params ["_sessionId", "_messageParameters"]; 939 | _messageParameters params ["_params","_functionName","_target",["_isCall",false]]; 940 | if(_functionName in AR_SUPPORTED_REMOTEEXECCLIENT_FUNCTIONS) then { 941 | if(_isCall) then { 942 | _params remoteExecCall [_functionName, _target]; 943 | } else { 944 | _params remoteExec [_functionName, _target]; 945 | }; 946 | }; 947 | }; 948 | 949 | }; 950 | 951 | diag_log "Advanced Rappelling Loaded"; 952 | 953 | }; 954 | 955 | publicVariable "AR_Advanced_Rappelling_Install"; 956 | 957 | [] call AR_Advanced_Rappelling_Install; 958 | // Install Advanced Rappelling on all clients (plus JIP) // 959 | remoteExecCall ["AR_Advanced_Rappelling_Install", -2,true]; 960 | -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/sounds/AR_Rappel_End.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/sounds/AR_Rappel_End.ogg -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/sounds/AR_Rappel_Loop.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/sounds/AR_Rappel_Loop.ogg -------------------------------------------------------------------------------- /addons/AR_AdvancedRappelling/sounds/AR_Rappel_Start.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/addons/AR_AdvancedRappelling/sounds/AR_Rappel_Start.ogg -------------------------------------------------------------------------------- /keys/AdvancedRappelling.bikey: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/keys/AdvancedRappelling.bikey -------------------------------------------------------------------------------- /logo.paa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/logo.paa -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/logo.png -------------------------------------------------------------------------------- /logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/logo.psd -------------------------------------------------------------------------------- /mod.cpp: -------------------------------------------------------------------------------- 1 | name = "Advanced Rappelling"; 2 | picture = "logo.paa"; 3 | description = "Advanced Rappelling"; 4 | logo = "logo.paa"; 5 | logoOver = "logo.paa"; 6 | tooltip = "Advanced Rappelling"; 7 | tooltipOwned = "Advanced Rappelling Owned"; 8 | overview = "Advanced Rappelling"; 9 | author = "[SA] Duda"; 10 | overviewPicture = "logo.paa"; 11 | overviewText = "Advanced Rappelling"; 12 | overviewFootnote = ""; -------------------------------------------------------------------------------- /screenshots/ss1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/screenshots/ss1.JPG -------------------------------------------------------------------------------- /screenshots/ss2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/screenshots/ss2.JPG -------------------------------------------------------------------------------- /screenshots/ss3.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/screenshots/ss3.JPG -------------------------------------------------------------------------------- /screenshots/ss4.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/screenshots/ss4.JPG -------------------------------------------------------------------------------- /steamLogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/steamLogo.jpg -------------------------------------------------------------------------------- /steamLogo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sethduda/AdvancedRappelling/414c0b23460b0e701e5e721748c50e555ebd5f50/steamLogo.psd --------------------------------------------------------------------------------