////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // SCRIPT NAME : rappel_public.sch // // AUTHOR : Rob Bray // // DESCRIPTION : Common functions for rappel // // // ////////////////////////////////////////////////////////////////////////////////////////////////////////// USING "rage_builtins.sch" USING "commands_misc.sch" USING "commands_pad.sch" USING "commands_script.sch" USING "commands_player.sch" USING "commands_vehicle.sch" USING "commands_object.sch" USING "commands_graphics.sch" USING "commands_physics.sch" USING "commands_streaming.sch" USING "commands_camera.sch" USING "commands_audio.sch" USING "script_player.sch" CONST_INT STICK_MOVEMENT_RAPPEL_DOWN 100 CONST_INT STICK_MOVEMENT_RAPPEL_SIDE 100 CONST_INT RAPPEL_HELP_DELAY 1500 CONST_FLOAT JUMP_DOWN_SPEED 4.0 CONST_FLOAT JUMP_DOWN_SPEED_ACCELERATING 9.0 CONST_FLOAT JUMP_DOWN_SPEED_BIG 13.0 CONST_FLOAT JUMP_DOWN_ACCELERATION 8.5 CONST_FLOAT JUMP_DOWN_BIG_ACCELERATION 25.0 CONST_FLOAT JUMP_DOWN_MIN_DECELERATION_SMALL 4.0 CONST_FLOAT JUMP_DOWN_MIN_DECELERATION_BIG 15.0 CONST_FLOAT JUMP_DOWN_MAX_DECELERATION_SMALL 24.0 CONST_FLOAT JUMP_DOWN_MAX_DECELERATION_BIG 30.0 CONST_FLOAT FAST_DECELERATION 40.0 CONST_FLOAT SLIDE_ACCEL 2.0 CONST_FLOAT SLIDE_DECEL 5.0 CONST_FLOAT DEFAULT_MAX_SLIDE_SPEED 3.0 CONST_FLOAT DEFAULT_MAX_FAST_SLIDE_SPEED 6.0 CONST_FLOAT JUMP_DOWN_START_MOVE_PHASE_BIG 0.045 CONST_FLOAT JUMP_DOWN_START_MOVE_PHASE 0.07 CONST_FLOAT JUMP_DOWN_END_MOVE_PHASE 0.76 CONST_FLOAT MAX_STRENGTH_JUMP_PHASE 0.30//0.12 CONST_FLOAT MIN_STOP_DESCEND_PHASE 0.30 CONST_FLOAT MAX_STOP_DESCEND_PHASE 0.65 CONST_FLOAT MIN_STOP_DESCEND_PHASE_BIG 0.30 CONST_FLOAT MAX_STOP_DESCEND_PHASE_BIG 0.61 CONST_FLOAT ALLOW_JUMP_DOWN_CONVERT_PHASE 0.2 CONST_FLOAT ALLOW_START_NEW_JUMP_PHASE 0.76 CONST_FLOAT DEFAULT_SMALL_JUMP_SPEED 1.0 CONST_FLOAT DEFAULT_BIG_JUMP_SPEED 0.75 CONST_FLOAT DEFAULT_JUMP_DOWN_SOUND_LENGTH 1.40 CONST_FLOAT DEFAULT_ROPE_WEIGHT 40.0 CONST_FLOAT RAPPEL_CAM_MAX_SPEED 2.6 CONST_FLOAT FREE_ROPE_HAND_OFFSET_X 0.1 CONST_FLOAT FREE_ROPE_HAND_OFFSET_Y 0.05 CONST_FLOAT DIRECT_PIN_NEXT_VERTEX_DIST 0.02 CONST_FLOAT VERTEX_INTERP_SPEED_MULT -0.741 CONST_FLOAT VERTEX_INTERP_SPEED_MOD 3.982 #IF IS_DEBUG_BUILD BOOL bDebugRappelInfo = FALSE #ENDIF ENUM RAPPEL_STATE_ENUM RAPPEL_STATE_IDLING = 0, RAPPEL_STATE_WALKING, RAPPEL_STATE_JUMPING_STATIC, RAPPEL_STATE_JUMPING_DOWN, RAPPEL_STATE_JUMPING_SIDEWAYS, RAPPEL_STATE_SLIDING, RAPPEL_STATE_TRANSITION_TO_FREE_ROPING, RAPPEL_STATE_DISMOUNT_FREE_ROPING ENDENUM ENUM RAPPEL_AI_ENUM RAPPEL_AI_STOP = 0, RAPPEL_AI_MOVE_SLOW, RAPPEL_AI_MOVE_FAST, RAPPEL_AI_SWING_LEFT, RAPPEL_AI_SWING_RIGHT ENDENUM ENUM RAPPEL_MATERIAL_ENUM RAPPEL_MATERIAL_METAL = 0, RAPPEL_MATERIAL_GLASS, RAPPEL_MATERIAL_STONE ENDENUM ENUM RAPPEL_SOUND_ENUM RAPPEL_SOUND_FEET_THUD = 0, RAPPEL_SOUND_RAPPEL, RAPPEL_SOUND_SWING_LAND, RAPPEL_SOUND_WALK_DOWN, RAPPEL_SOUND_FREE_ROPE ENDENUM STRUCT RAPPEL_DATA RAPPEL_STATE_ENUM state RAPPEL_AI_ENUM ai RAPPEL_MATERIAL_ENUM material PED_INDEX ped CAMERA_INDEX cam ROPE_INDEX rope OBJECT_INDEX anchorObject OBJECT_INDEX weightObject OBJECT_INDEX pulleyObject WEAPON_TYPE dismountWeapon VECTOR vAttachPos VECTOR vOverrideHand VECTOR vOverrideRopeOrigin VECTOR vCacheHand FLOAT fSpeed FLOAT fSideJumpSpeed FLOAT fCurrentJumpStrength FLOAT fJumpDeceleration FLOAT fStopDescendPhase FLOAT fLimitZ FLOAT fSlowDownByLimitRange FLOAT fMaxSlideSpeed FLOAT fLength FLOAT fRopeSegmentLength FLOAT fOverrideMaxJumpPhase FLOAT fOverrideBigJumpSpeed FLOAT fOverrideSmallJumpSpeed // cam detals FLOAT fTargetCamHeight FLOAT fCurrentCamHeight FLOAT fTargetCamHeading FLOAT fCurrentCamHeading FLOAT fCamDefaultHeading FLOAT fCamYDist FLOAT fCamXYInputToDegreesFactor FLOAT fCamClockwiseLimit FLOAT fCamAnticlockwiseLimit FLOAT fCamXYSpeed FLOAT fCamZDist FLOAT fCamZInputToHeightFactor FLOAT fCamZUpperLimit FLOAT fCamZLowerLimit FLOAT fCamZSpeed FLOAT fCamZMod FLOAT fCamFOV VECTOR vModifyCamPointAt // end cam details BOOL bRappelling BOOL bFreeRoping BOOL bRopeCreated BOOL bAllowRopeMovement BOOL bUnfurling BOOL bAttachedWeight BOOL bDirectlyPinNextVertex BOOL bSetupCam BOOL bShownHelp BOOL bAllowSmallJumps BOOL bAllowBigJumps BOOL bAllowSideJumps BOOL bForceSmallJumpOnBigJumpControl BOOL bSetBigJumpControlAsNormal BOOL bCurrentJumpIsBig BOOL bCurrentSideJumpIsRight BOOL bPinnedLastVertex BOOL bOverrideRopeOrigin BOOL bUsePulley BOOL bUnpinnedForDismount BOOL bResetRunFromFiresAndExplosionsFlagOnCancel BOOL bResetDisableExplosionReactionsFlagOnCancel BOOL bDisabledPainAudio BOOL bDoneLandGrunt BOOL bUseOlderRappelJumps BOOL bSuppressUnpinAllVertices INT iSoundID[COUNT_OF(RAPPEL_SOUND_ENUM)] INT iJumpStartTime INT iSetStateTime INT iLastRopeVertex INT iNextRopeVertex INT iRopeVertexCount INT iLastVertexTime // To adjust the camera limits for mouse. FLOAT fMouseLimitXYMultiplier = 1.0 FLOAT fMouseLimitZMultiplier = 1.0 FLOAT fMouseSensitivityX = 0.1 FLOAT fMouseSensitivityY = 0.005 ENDSTRUCT // anim dictionary of rappel animations FUNC STRING GET_RAPPEL_ANIM_DICT_NAME() RETURN "MISSRAPPEL" ENDFUNC // are rappel anims loaded in? FUNC BOOL HAVE_RAPPEL_ANIMS_LOADED() IF HAS_ANIM_DICT_LOADED(GET_RAPPEL_ANIM_DICT_NAME()) RETURN TRUE ENDIF RETURN FALSE ENDFUNC // request rappel anims (optional wait for load) PROC REQUEST_RAPPEL_ANIMS(BOOL bWaitForLoad = FALSE) REQUEST_ANIM_DICT(GET_RAPPEL_ANIM_DICT_NAME()) IF bWaitForLoad WHILE NOT HAVE_RAPPEL_ANIMS_LOADED() WAIT(0) ENDWHILE ENDIF ENDPROC // model name of rappel anchor FUNC MODEL_NAMES GET_RAPPEL_ANCHOR_MODEL_NAME() RETURN Prop_LD_Test_01 ENDFUNC // model name of rappel pulley FUNC MODEL_NAMES GET_RAPPEL_PULLEY_MODEL_NAME() RETURN P_RPulley_S ENDFUNC // is anchor model loaded in? FUNC BOOL HAS_RAPPEL_ANCHOR_MODEL_LOADED() IF HAS_MODEL_LOADED(GET_RAPPEL_ANCHOR_MODEL_NAME()) RETURN TRUE ENDIF RETURN FALSE ENDFUNC // is pulley model loaded in? FUNC BOOL HAS_RAPPEL_PULLEY_MODEL_LOADED() IF HAS_MODEL_LOADED(GET_RAPPEL_PULLEY_MODEL_NAME()) RETURN TRUE ENDIF RETURN FALSE ENDFUNC // request anchor model (optional wait for load) PROC REQUEST_RAPPEL_ANCHOR_MODEL(BOOL bWaitForLoad = FALSE) REQUEST_MODEL(GET_RAPPEL_ANCHOR_MODEL_NAME()) IF bWaitForLoad WHILE NOT HAS_RAPPEL_ANCHOR_MODEL_LOADED() WAIT(0) ENDWHILE ENDIF ENDPROC // request pulley model (optional wait for load) PROC REQUEST_RAPPEL_PULLEY_MODEL(BOOL bWaitForLoad = FALSE) REQUEST_MODEL(GET_RAPPEL_PULLEY_MODEL_NAME()) IF bWaitForLoad WHILE NOT HAS_RAPPEL_PULLEY_MODEL_LOADED() WAIT(0) ENDWHILE ENDIF ENDPROC /* // name of rappel bank FUNC STRING GET_RAPPEL_AUDIO_BANK_NAME() RETURN "Abseiling" ENDFUNC // is audio loaded in? FUNC BOOL HAS_RAPPEL_AUDIO_LOADED() IF REQUEST_SCRIPT_AUDIO_BANK(GET_RAPPEL_AUDIO_BANK_NAME()) RETURN TRUE ENDIF RETURN FALSE ENDFUNC // request rappel audio (optional wait for load) PROC REQUEST_RAPPEL_AUDIO(BOOL bWaitForLoad = FALSE) REQUEST_SCRIPT_AUDIO_BANK(GET_RAPPEL_AUDIO_BANK_NAME()) IF bWaitForLoad WHILE NOT HAS_RAPPEL_AUDIO_LOADED() WAIT(0) ENDWHILE ENDIF ENDPROC */ // request rappel assets (optional wait for load) PROC REQUEST_RAPPEL_ASSETS(BOOL bWaitForLoad = FALSE, BOOL bHandleEnableTextures = TRUE) REQUEST_RAPPEL_ANIMS(bWaitForLoad) REQUEST_RAPPEL_ANCHOR_MODEL(bWaitForLoad) REQUEST_RAPPEL_PULLEY_MODEL(bWaitForLoad) IF bHandleEnableTextures ROPE_LOAD_TEXTURES() IF bWaitForLoad WHILE NOT ROPE_ARE_TEXTURES_LOADED() WAIT(0) ENDWHILE ENDIF ENDIF ENDPROC // have rappel assets loaded? FUNC BOOL HAVE_RAPPEL_ASSETS_LOADED(BOOL bCheckTextures = TRUE) IF HAVE_RAPPEL_ANIMS_LOADED() AND HAS_RAPPEL_ANCHOR_MODEL_LOADED() AND HAS_RAPPEL_PULLEY_MODEL_LOADED() AND (ROPE_ARE_TEXTURES_LOADED() OR NOT bCheckTextures) RETURN TRUE ENDIF RETURN FALSE ENDFUNC // release any rappel audio /* PROC RELEASE_RAPPEL_AUDIO(RAPPEL_DATA &rappelData) INT i REPEAT COUNT_OF(RAPPEL_SOUND_ENUM) i IF rappelData.iSoundID[i] <> 0 RELEASE_SOUND_ID(rappelData.iSoundID[i]) rappelData.iSoundID[i] = 0 ENDIF ENDREPEAT ENDPROC */ // set rappel assets no longer needed PROC SET_RAPPEL_ASSETS_AS_NO_LONGER_NEEDED(BOOL bHandleDisableTextures = TRUE) REMOVE_ANIM_DICT(GET_RAPPEL_ANIM_DICT_NAME()) SET_MODEL_AS_NO_LONGER_NEEDED(GET_RAPPEL_ANCHOR_MODEL_NAME()) SET_MODEL_AS_NO_LONGER_NEEDED(GET_RAPPEL_PULLEY_MODEL_NAME()) IF bHandleDisableTextures ROPE_UNLOAD_TEXTURES() ENDIF //RELEASE_NAMED_SCRIPT_AUDIO_BANK(GET_RAPPEL_AUDIO_BANK_NAME()) ENDPROC // stop a rappel sound /* PROC STOP_RAPPEL_SOUND(RAPPEL_DATA &rappelData, RAPPEL_SOUND_ENUM sound) STOP_SOUND(rappelData.iSoundID[sound]) ENDPROC // stop rappel sound PROC STOP_ALL_RAPPEL_SOUND(RAPPEL_DATA &rappelData, BOOL bCancelFreeRopeSound) INT i REPEAT COUNT_OF(RAPPEL_SOUND_ENUM) i STOP_RAPPEL_SOUND(rappelData, INT_TO_ENUM(RAPPEL_SOUND_ENUM, i)) ENDREPEAT IF bCancelFreeRopeSound ENDIF ENDPROC */ // play rappel sound /* PROC PLAY_RAPPEL_SOUND(RAPPEL_DATA &rappelData, RAPPEL_SOUND_ENUM sound) TEXT_LABEL_31 tSound TEXT_LABEL_31 tSoundSet SWITCH sound CASE RAPPEL_SOUND_FEET_THUD tSound = "Feet_Thud" BREAK CASE RAPPEL_SOUND_RAPPEL tSound = "Rappel" BREAK CASE RAPPEL_SOUND_SWING_LAND tSound = "Swing_Land" BREAK CASE RAPPEL_SOUND_WALK_DOWN tSound = "Walk_Down" BREAK CASE RAPPEL_SOUND_FREE_ROPE tSound = "Free_Rope" BREAK ENDSWITCH // add material? IF rappelData.ped = PLAYER_PED_ID() SWITCH rappelData.material CASE RAPPEL_MATERIAL_GLASS tSoundSet = "Abseiling_Player_Glass" BREAK CASE RAPPEL_MATERIAL_METAL tSoundSet = "Abseiling_Player_Metal" BREAK CASE RAPPEL_MATERIAL_STONE tSoundSet = "Abseiling_Player_Stone" BREAK ENDSWITCH ELSE SWITCH rappelData.material CASE RAPPEL_MATERIAL_GLASS tSoundSet = "Abseiling_NPC_Glass" BREAK CASE RAPPEL_MATERIAL_METAL tSoundSet = "Abseiling_NPC_Metal" BREAK CASE RAPPEL_MATERIAL_STONE tSoundSet = "Abseiling_NPC_Stone" BREAK ENDSWITCH ENDIF SWITCH sound CASE RAPPEL_SOUND_RAPPEL STOP_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_SWING_LAND) STOP_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_WALK_DOWN) BREAK ENDSWITCH IF HAS_SOUND_FINISHED(rappelData.iSoundID[sound]) PLAY_SOUND_FROM_ENTITY(rappelData.iSoundID[sound], tSound, rappelData.ped, tSoundSet) ENDIF ENDPROC */ FUNC CONTROL_ACTION GET_NORMAL_JUMP_CONTROL() RETURN INPUT_SCRIPT_RDOWN ENDFUNC FUNC CONTROL_ACTION GET_BIG_JUMP_CONTROL() RETURN INPUT_SCRIPT_RLEFT ENDFUNC PROC PLAY_PUSH_OFF_PAIN(RAPPEL_DATA &rappelData) IF NOT rappelData.bDisabledPainAudio IF rappelData.ped = PLAYER_PED_ID() IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF GET_RANDOM_INT_IN_RANGE(0,2) = 0 PLAY_PAIN(PLAYER_PED_ID(), AUD_DAMAGE_REASON_CLIMB_SMALL,0) ELSE PLAY_PAIN(PLAYER_PED_ID(), AUD_DAMAGE_REASON_CLIMB_LARGE,0) ENDIF ENDIF ENDIF ENDIF ENDPROC // set rappel state PROC SET_RAPPEL_STATE(RAPPEL_DATA &rappelData, RAPPEL_STATE_ENUM newRappelState, BOOL bForceState = FALSE, BOOL bAllowResetStage = FALSE, BOOL bPlayAnim = TRUE, FLOAT fInitPhase = 0.0, BOOL bForceSlowBlendIn = FALSE) IF rappelData.state = newRappelState AND NOT bAllowResetStage AND NOT bForceState // don't do anything if already in desired state EXIT ENDIF IF NOT IS_PED_INJURED(rappelData.ped) IF bPlayAnim STRING sAnim STRING sPulleyAnim FLOAT fBlendIn = NORMAL_BLEND_IN FLOAT fBlendOut = NORMAL_BLEND_OUT IF bForceState fBlendIn = INSTANT_BLEND_IN ENDIF IF bForceSlowBlendIn fBlendIn = 2.0 ENDIF SWITCH newRappelState CASE RAPPEL_STATE_IDLING ANIMATION_FLAGS animFlags IF bForceState animFlags = AF_LOOPING | AF_FORCE_START ELSE animFlags = AF_LOOPING ENDIF IF rappelData.bFreeRoping sAnim = "Rope_Idle" ELSE sAnim = "Rappel_Idle" sPulleyAnim = "Rappel_Idle_prop" ENDIF TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), sAnim, fBlendIn, fBlendOut, -1, animFlags, fInitPhase) rappelData.fSpeed = 0.0 IF NOT rappelData.bFreeRoping IF DOES_ENTITY_EXIST(rappelData.pulleyObject) IF DOES_ENTITY_HAVE_DRAWABLE(rappelData.pulleyObject) PLAY_ENTITY_ANIM(rappelData.pulleyObject, sPulleyAnim, GET_RAPPEL_ANIM_DICT_NAME(), fBlendIn, TRUE, FALSE) ENDIF ENDIF ENDIF //STOP_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_FEET_THUD) //STOP_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_WALK_DOWN) //STOP_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_SWING_LAND) //STOP_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_FREE_ROPE) BREAK CASE RAPPEL_STATE_WALKING IF bForceState animFlags = AF_LOOPING | AF_FORCE_START ELSE animFlags = AF_LOOPING ENDIF TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Walk", fBlendIn, fBlendOut, -1, animFlags, fInitPhase) IF DOES_ENTITY_EXIST(rappelData.pulleyObject) IF DOES_ENTITY_HAVE_DRAWABLE(rappelData.pulleyObject) PLAY_ENTITY_ANIM(rappelData.pulleyObject, "Rappel_Walk_prop", GET_RAPPEL_ANIM_DICT_NAME(), fBlendIn, TRUE, FALSE) ENDIF ENDIF //PLAY_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_WALK_DOWN) BREAK CASE RAPPEL_STATE_JUMPING_STATIC IF bForceState animFlags = AF_HOLD_LAST_FRAME | AF_FORCE_START ELSE animFlags = AF_HOLD_LAST_FRAME ENDIF TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_a", fBlendIn, fBlendOut, -1, animFlags, fInitPhase) IF DOES_ENTITY_EXIST(rappelData.pulleyObject) IF DOES_ENTITY_HAVE_DRAWABLE(rappelData.pulleyObject) PLAY_ENTITY_ANIM(rappelData.pulleyObject, "Rappel_Jump_a_prop", GET_RAPPEL_ANIM_DICT_NAME(), fBlendIn, FALSE, TRUE) ENDIF ENDIF PLAY_PUSH_OFF_PAIN(rappelData) rappelData.bDoneLandGrunt = FALSE rappelData.fCurrentJumpStrength = 0.0 rappelData.fStopDescendPhase = -1.0 rappelData.fJumpDeceleration = JUMP_DOWN_MAX_DECELERATION_SMALL //PLAY_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_SWING_LAND) BREAK CASE RAPPEL_STATE_JUMPING_DOWN IF bForceState animFlags = AF_HOLD_LAST_FRAME | AF_FORCE_START ELSE animFlags = AF_HOLD_LAST_FRAME ENDIF IF rappelData.bCurrentJumpIsBig IF NOT rappelData.bUseOlderRappelJumps sAnim = "rappel_jump_c" sPulleyAnim = "Rappel_Jump_c_Prop" ELSE sAnim = "rappel_jump_a" sPulleyAnim = "Rappel_Jump_a_Prop" ENDIF ELSE sAnim = "Rappel_Jump_a" sPulleyAnim = "Rappel_Jump_a_prop" ENDIF TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), sAnim, fBlendIn, fBlendOut, -1, animFlags, fInitPhase) IF DOES_ENTITY_EXIST(rappelData.pulleyObject) IF DOES_ENTITY_HAVE_DRAWABLE(rappelData.pulleyObject) PLAY_ENTITY_ANIM(rappelData.pulleyObject, sPulleyAnim, GET_RAPPEL_ANIM_DICT_NAME(), fBlendIn, FALSE, TRUE) ENDIF ENDIF PLAY_PUSH_OFF_PAIN(rappelData) rappelData.bDoneLandGrunt = FALSE //PLAY_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_RAPPEL) rappelData.fCurrentJumpStrength = 0.0 rappelData.fStopDescendPhase = -1.0 rappelData.fJumpDeceleration = JUMP_DOWN_MAX_DECELERATION_SMALL rappelData.iJumpStartTime = GET_GAME_TIMER() BREAK CASE RAPPEL_STATE_JUMPING_SIDEWAYS IF bForceState animFlags = AF_LOOPING | AF_FORCE_START ELSE animFlags = AF_LOOPING ENDIF PLAY_PUSH_OFF_PAIN(rappelData) rappelData.bDoneLandGrunt = FALSE TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Walk", fBlendIn, fBlendOut, -1, animFlags, fInitPhase) BREAK CASE RAPPEL_STATE_SLIDING IF bForceState animFlags = AF_LOOPING | AF_FORCE_START ELSE animFlags = AF_LOOPING ENDIF TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rope_Slide", fBlendIn, fBlendOut, -1, animFlags, fInitPhase) //PLAY_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_FREE_ROPE) BREAK CASE RAPPEL_STATE_TRANSITION_TO_FREE_ROPING IF bForceState animFlags = AF_HOLD_LAST_FRAME | AF_FORCE_START ELSE animFlags = AF_HOLD_LAST_FRAME ENDIF TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_to_free_rope", fBlendIn, fBlendOut, -1, animFlags, fInitPhase) BREAK CASE RAPPEL_STATE_DISMOUNT_FREE_ROPING IF bForceState animFlags = AF_FORCE_START ELSE animFlags = AF_DEFAULT ENDIF DETACH_ENTITY(rappelData.ped) TASK_PLAY_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "land_action", fBlendIn, fBlendOut, -1, animFlags, fInitPhase) BREAK ENDSWITCH ENDIF IF bForceState FORCE_PED_AI_AND_ANIMATION_UPDATE(rappelData.ped) ENDIF ENDIF rappelData.iSetStateTime = GET_GAME_TIMER() rappelData.state = newRappelState ENDPROC /// PURPOSE: /// Sets multiplier values for the mouse limits /// PARAMS: /// rappelData - Rappel data struct /// fXYLimit - Limit multiplier for horizontal movement /// fZLimit - Limit multiplier for vertical movement PROC INIT_RAPPEL_CAM_MOUSE_PARAMS( RAPPEL_DATA &rappelData, FLOAT fXYLimit, FLOAT fZLimit, FLOAT fMouseSensitivityX = 0.1, FLOAT fMouseSensitivityY = 0.005 ) rappelData.fMouseLimitXYMultiplier = fXYLimit rappelData.fMouseLimitZMultiplier = fZLimit rappelData.fMouseSensitivityX = fMouseSensitivityX rappelData.fMouseSensitivityY = fMouseSensitivityY ENDPROC // initialise rappel camera with properties PROC SETUP_RAPPEL_CAM(RAPPEL_DATA &rappelData, VECTOR vCamPos, BOOL bCreateCam = TRUE, BOOL bStartRenderingRappelCam = TRUE) IF NOT IS_PED_INJURED(rappelData.ped) IF bCreateCam IF DOES_CAM_EXIST(rappelData.cam) DESTROY_CAM(rappelData.cam) ENDIF rappelData.cam = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA", TRUE) SET_CAM_PARAMS(rappelData.cam, vCamPos, <<0,0,0>>, rappelData.fCamFOV) POINT_CAM_AT_ENTITY(rappelData.cam, rappelData.ped,<<0,0,0>>) IF bStartRenderingRappelCam DISPLAY_HUD(FALSE) DISPLAY_RADAR(TRUE) RENDER_SCRIPT_CAMS(TRUE,FALSE) ENDIF ENDIF ENDIF rappelData.bSetupCam = TRUE ENDPROC // do rappel cam PROC DO_RAPPEL_CAM(RAPPEL_DATA &rappelData, BOOL bForceCurrentPosUpdate = FALSE, INT iRX = 0, INT iRY = 0, BOOL bUpdateFromControls = TRUE, FLOAT fForceInitialOffset = -1000.0, BOOL bStartRenderingRappelCam = TRUE) IF NOT IS_PED_INJURED(rappelData.ped) PROCESS_ENTITY_ATTACHMENTS(rappelData.ped) FLOAT fTimeSinceLastFrame = GET_FRAME_TIME() FLOAT fPedHeading = GET_ENTITY_HEADING(rappelData.ped) //VECTOR vPedCoords = GET_ENTITY_COORDS(rappelData.ped) IF fPedHeading < 0 fPedHeading += 360.0 ENDIF IF bUpdateFromControls IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) // Reduce limits to prevent clipping when using mouse. FLOAT fMouseCamAnticlockwiseLimit = rappelData.fCamAnticlockwiseLimit * rappelData.fMouseLimitXYMultiplier FLOAT fMouseCamClockwiseLimit = rappelData.fCamClockwiseLimit * rappelData.fMouseLimitXYMultiplier rappelData.fTargetCamHeading += (iRX * rappelData.fMouseSensitivityX) IF rappelData.fTargetCamHeading > fMouseCamAnticlockwiseLimit rappelData.fTargetCamHeading = fMouseCamAnticlockwiseLimit ELIF rappelData.fTargetCamHeading < -fMouseCamClockwiseLimit rappelData.fTargetCamHeading = -fMouseCamClockwiseLimit ENDIF ELSE rappelData.fTargetCamHeading = (-iRX * rappelData.fCamXYInputToDegreesFactor) IF rappelData.fTargetCamHeading > rappelData.fCamAnticlockwiseLimit rappelData.fTargetCamHeading = rappelData.fCamAnticlockwiseLimit ELIF rappelData.fTargetCamHeading < -rappelData.fCamClockwiseLimit rappelData.fTargetCamHeading = -rappelData.fCamClockwiseLimit ENDIF ENDIF // No need to invert on mouse IF IS_LOOK_INVERTED() AND NOT IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) iRY *= -1 ENDIF // Debug for mouse // DISPLAY_TEXT_WITH_FLOAT(0.0,0.0, "NUMBER", rappelData.fCamZUpperLimit, 3) // DISPLAY_TEXT_WITH_FLOAT(0.0,0.1, "NUMBER", rappelData.fCamZLowerLimit, 3) // DISPLAY_TEXT_WITH_FLOAT(0.0,0.2, "NUMBER", rappelData.fTargetCamHeight, 3) IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) FLOAT fMouseCamZUpperLimit = rappelData.fCamZUpperLimit * rappelData.fMouseLimitZMultiplier FLOAT fMouseCamZLowerLimit = rappelData.fCamZLowerLimit * rappelData.fMouseLimitZMultiplier rappelData.fTargetCamHeight -= (iRY * rappelData.fMouseSensitivityY) // 0.005 IF rappelData.fTargetCamHeight > fMouseCamZUpperLimit rappelData.fTargetCamHeight = fMouseCamZUpperLimit ELIF rappelData.fTargetCamHeight < fMouseCamZLowerLimit rappelData.fTargetCamHeight = fMouseCamZLowerLimit ENDIF ELSE rappelData.fTargetCamHeight = iRY * rappelData.fCamZInputToHeightFactor IF rappelData.fTargetCamHeight > rappelData.fCamZUpperLimit rappelData.fTargetCamHeight = rappelData.fCamZUpperLimit ELIF rappelData.fTargetCamHeight < rappelData.fCamZLowerLimit rappelData.fTargetCamHeight = rappelData.fCamZLowerLimit ENDIF ENDIF // Mouse uses faster interpolation for speed of response. IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) FLOAT fMouseCamXYSpeed = rappelData.fCamXYSpeed * 20 FLOAT fMouseCamZSpeed = rappelData.fCamZSpeed * 5 rappelData.fCamZMod += (rappelData.fTargetCamHeight - rappelData.fCamZMod) * (fMouseCamZSpeed * fTimeSinceLastFrame) rappelData.fCurrentCamHeading += (rappelData.fTargetCamHeading - rappelData.fCurrentCamHeading) * (fMouseCamXYSpeed * fTimeSinceLastFrame) ELSE rappelData.fCamZMod += (rappelData.fTargetCamHeight - rappelData.fCamZMod) * (rappelData.fCamZSpeed * fTimeSinceLastFrame) rappelData.fCurrentCamHeading += (rappelData.fTargetCamHeading - rappelData.fCurrentCamHeading) * (rappelData.fCamXYSpeed * fTimeSinceLastFrame) ENDIF ENDIF rappelData.fCurrentCamHeight = rappelData.fCamZDist + rappelData.fCamZMod // get the distance between the mover and the root VECTOR vOffsetFromMover IF fForceInitialOffset <= -1000 vOffsetFromMover = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(rappelData.ped, GET_PED_BONE_COORDS(rappelData.ped, BONETAG_ROOT, <<0,0,0>>)) vOffsetFromMover.y /= 4 //printstring("voffsetfrommover = ") printfloat(vOffsetFromMover.y) printnl() ELSE vOffsetFromMover.y = fForceInitialOffset ENDIF VECTOR vPedCoordsWithOffset = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(rappelData.ped, <<0,vOffsetFromMover.y,0>>) //printstring("vpedcoords with offset = ") printvector(vPedCoordsWithOffset) PRINTNL() VECTOR vCurrentCamPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPedCoordsWithOffset, rappelData.fCurrentCamHeading + rappelData.fCamDefaultHeading + fPedHeading , <<0, rappelData.fCamYDist, 0>>) VECTOR vReconvertedPos = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(rappelData.ped, vCurrentCamPos) IF NOT rappelData.bSetupCam OR bForceCurrentPosUpdate SETUP_RAPPEL_CAM(rappelData, vCurrentCamPos, NOT bForceCurrentPosUpdate, bStartRenderingRappelCam) ENDIF //VECTOR vNewAttach = <> //PRINTSTRING("newattach") PRINTVECTOR(vNewAttach) PRINTNL() vReconvertedPos.z = rappelData.fCurrentCamHeight ATTACH_CAM_TO_ENTITY(rappelData.cam, rappelData.ped, vReconvertedPos, TRUE)//GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(rappelData.ped, vPedCoordsWithOffset)) POINT_CAM_AT_ENTITY(rappelData.cam, rappelData.ped, <<0,vOffsetFromMover.y,0.6>> + rappelData.vModifyCamPointAt) //POINT_CAM_AT_COORD(rappelData.cam, GET_ENTITY_COORDS(rappelData.ped)) SET_CAM_PARAMS(rappelData.cam, vCurrentCamPos, <<0,0,0>>, rappelData.fCamFOV) //SET_CAM_PARAMS(GET_GAME_CAM(), GET_CAM_POS(rappelData.cam), GET_CAM_ROT(rappelData.cam)) //SET_GAMEPLAY_CAM_RELATIVE_HEADING(rappelData.fCurrentCamHeading + rappelData.fCamDefaultHeading) SET_CAM_CONTROLS_MINI_MAP_HEADING(rappelData.cam, TRUE) ENDIF ENDPROC // should rappel jump be moving at current anim phase FUNC BOOL SHOULD_RAPPEL_JUMP_BE_MOVING(RAPPEL_DATA rappelData, FLOAT fAnimPhase) IF rappelData.state = RAPPEL_STATE_JUMPING_DOWN IF rappelData.bCurrentJumpIsBig AND NOT rappelData.bUseOlderRappelJumps IF fAnimPhase >= JUMP_DOWN_START_MOVE_PHASE_BIG AND fAnimPhase <= JUMP_DOWN_END_MOVE_PHASE RETURN TRUE ENDIF ELSE IF fAnimPhase >= JUMP_DOWN_START_MOVE_PHASE AND fAnimPhase <= JUMP_DOWN_END_MOVE_PHASE RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC // is free roping done FUNC BOOL HAS_FREE_ROPING_FINISHED(RAPPEL_DATA &rappelData, BOOL bCheckPedHasStopped = FALSE) IF rappelData.vAttachPos.z <= rappelData.fLimitZ IF rappelData.fSpeed = 0.0 OR NOT bCheckPedHasStopped RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC // is a ped dismounting FUNC BOOL IS_RAPPEL_DISMOUNTING(RAPPEL_DATA &rappelData) IF NOT IS_PED_INJURED(rappelData.ped) IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "land_action") OR GET_GAME_TIMER() <= rappelData.iSetStateTime + 500 RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC // convert to free roping FUNC BOOL CONVERT_RAPPEL_IS_FREE_ROPING(RAPPEL_DATA &rappelData, BOOL bToFreeRoping) IF rappelData.state = RAPPEL_STATE_IDLING IF NOT IS_PED_INJURED(rappelData.ped) IF bToFreeRoping AND NOT rappelData.bFreeRoping //rappelData.bFreeRoping = TRUE SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_TRANSITION_TO_FREE_ROPING, FALSE, TRUE) ELIF rappelData.bFreeRoping AND NOT bToFreeRoping rappelData.bFreeRoping = FALSE SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING, FALSE, TRUE) ENDIF RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC // unpin all except anchor PROC UNPIN_ALL_ROPE_VERTICES_EXCEPT_ANCHOR(RAPPEL_DATA &rappelData) INT i IF NOT rappelData.bSuppressUnpinAllVertices IF DOES_ROPE_EXIST(rappelData.rope) REPEAT rappelData.iRopeVertexCount i IF i <> 0 UNPIN_ROPE_VERTEX(rappelData.rope, i) ENDIF ENDREPEAT ENDIF ENDIF ENDPROC // cancel rappel PROC CANCEL_RAPPEL(RAPPEL_DATA &rappelData, BOOL bCancelIntoCutscene = FALSE, WEAPON_TYPE restoreWeapon = WEAPONTYPE_UNARMED, BOOL bUnpin = TRUE, BOOL bClearTasks = TRUE, BOOL bDestroyPulley = TRUE) IF rappelData.bRappelling //STOP_ALL_RAPPEL_SOUND(rappelData, TRUE) IF NOT IS_PED_INJURED(rappelData.ped) IF rappelData.ped <> PLAYER_PED_ID() IF rappelData.bResetRunFromFiresAndExplosionsFlagOnCancel SET_PED_CONFIG_FLAG(rappelData.ped, PCF_RunFromFiresAndExplosions, TRUE) ENDIF IF rappelData.bResetDisableExplosionReactionsFlagOnCancel SET_PED_CONFIG_FLAG(rappelData.ped, PCF_DisableExplosionReactions, FALSE) ENDIF ENDIF IF IS_ENTITY_ATTACHED(rappelData.ped) IF NOT IS_PED_IN_ANY_VEHICLE(rappelData.ped) DETACH_ENTITY(rappelData.ped) IF bClearTasks CLEAR_PED_TASKS(rappelData.ped) ENDIF ENDIF ENDIF ENDIF IF DOES_CAM_EXIST(rappelData.cam) SET_CAM_ACTIVE(rappelData.cam, FALSE) rappelData.bSetupCam = FALSE ENDIF IF rappelData.ped = PLAYER_PED_ID() IF NOT bCancelIntoCutscene SET_PLAYER_CONTROL(PLAYER_ID(),TRUE) SET_GAMEPLAY_CAM_RELATIVE_HEADING(0) RENDER_SCRIPT_CAMS(FALSE, FALSE) DISPLAY_HUD(TRUE) DISPLAY_RADAR(TRUE) ENDIF ENDIF IF bDestroyPulley IF DOES_ENTITY_EXIST(rappelData.pulleyObject) DELETE_OBJECT(rappelData.pulleyObject) ENDIF ENDIF IF restoreWeapon <> WEAPONTYPE_UNARMED IF HAS_PED_GOT_WEAPON(rappelData.ped, restoreWeapon) SET_CURRENT_PED_WEAPON(rappelData.ped, restoreWeapon, TRUE) ENDIF ENDIF IF bUnpin UNPIN_ALL_ROPE_VERTICES_EXCEPT_ANCHOR(rappelData) ENDIF //IF NOT IS_PED_INJURED(rappelData.ped) // SET_ENTITY_ROTATION(rappelData.ped,<<0,0,GET_ENTITY_HEADING(rappelData.ped)>>) //ENDIF rappelData.bRappelling = FALSE ENDIF ENDPROC // handle the player controlling the player character to move PROC HANDLE_RAPPEL_PED(RAPPEL_DATA &rappelData, BOOL bIsAI = FALSE, BOOL bDoCam = TRUE, BOOL bAllowResetToIdle = TRUE, BOOL bAllowRapidConvertJump = TRUE, BOOL bForceSlowJumpDown = FALSE) INT iLX, iLY, iRX, iRY FLOAT fAnimPhase IF rappelData.ped = PLAYER_PED_ID() // southpaw control allowed ALLOW_ALTERNATIVE_SCRIPT_CONTROLS_LAYOUT(PLAYER_CONTROL) ALLOW_ALTERNATIVE_SCRIPT_CONTROLS_LAYOUT(FRONTEND_CONTROL) //printstring("SOUTHPAW") printnl() ENDIF IF NOT bIsAI OR bDoCam GET_CONTROL_VALUE_OF_ANALOGUE_STICKS(iLX, iLY, iRX, iRY) IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) iRX = FLOOR(GET_CONTROL_UNBOUND_NORMAL(FRONTEND_CONTROL, INPUT_SCALED_LOOK_LR) * 127) iRY = FLOOR(GET_CONTROL_UNBOUND_NORMAL(FRONTEND_CONTROL, INPUT_SCALED_LOOK_UD) * 127) ENDIF ENDIF IF bDoCam DO_RAPPEL_CAM(rappelData, FALSE, iRX, iRY) ENDIF BOOL bDoRappelAction = FALSE IF DOES_ENTITY_EXIST(rappelData.anchorObject) AND NOT IS_PED_INJURED(rappelData.ped) SWITCH rappelData.state CASE RAPPEL_STATE_IDLING IF NOT rappelData.bUnfurling IF NOT rappelData.bFreeRoping IF bIsAi IF rappelData.ai = RAPPEL_AI_MOVE_SLOW bDoRappelAction = TRUE ENDIF ELSE IF iLY > STICK_MOVEMENT_RAPPEL_DOWN bDoRappelAction = TRUE ENDIF ENDIF IF bDoRappelAction // walk down if pressing stick down IF rappelData.vAttachPos.z > rappelData.fLimitZ SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_WALKING) ENDIF ENDIF ELSE IF bIsAi IF rappelData.ai = RAPPEL_AI_MOVE_FAST bDoRappelAction = TRUE ENDIF ELSE IF IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, GET_NORMAL_JUMP_CONTROL()) OR (IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, GET_BIG_JUMP_CONTROL()) AND rappelData.bSetBigJumpControlAsNormal) bDoRappelAction = TRUE ENDIF ENDIF IF bDoRappelAction IF NOT HAS_FREE_ROPING_FINISHED(rappelData) OR rappelData.ped = PLAYER_PED_ID() SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_SLIDING) ENDIF ENDIF ENDIF ENDIF BREAK CASE RAPPEL_STATE_WALKING // pop back into idle if not pressed IF bIsAI IF rappelData.ai <> RAPPEL_AI_MOVE_SLOW bDoRappelAction = TRUE ENDIF ELSE IF iLY < STICK_MOVEMENT_RAPPEL_DOWN bDoRappelAction = TRUE ENDIF ENDIF BOOL bAtLimit bAtLimit = FALSE IF rappelData.vAttachPos.z <= rappelData.fLimitZ bDoRappelAction = TRUE bAtLimit = TRUE ENDIF IF bDoRappelAction IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Walk") fAnimPhase = GET_ENTITY_ANIM_CURRENT_TIME(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Walk") IF (fAnimPhase >= 0.96 AND fAnimPhase <= 1.0) SET_ENTITY_ANIM_SPEED(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_walk", 0.5) SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ELIF bAtLimit SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING, FALSE, FALSE, TRUE, 0, TRUE) ENDIF ELSE SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ENDIF ENDIF BREAK CASE RAPPEL_STATE_JUMPING_SIDEWAYS // when anim finished, go back to idle CONST_FLOAT SIDE_JUMP_DECELERATION 3.0 // swinging out IF rappelData.bCurrentSideJumpIsRight rappelData.fSideJumpSpeed = rappelData.fSideJumpSpeed -@ SIDE_JUMP_DECELERATION ELSE rappelData.fSideJumpSpeed = rappelData.fSideJumpSpeed +@ SIDE_JUMP_DECELERATION ENDIF rappelData.vAttachPos.x = rappelData.vAttachPos.x +@ rappelData.fSideJumpSpeed IF rappelData.bCurrentSideJumpIsRight IF rappelData.vAttachPos.x < 0.0 rappelData.vAttachPos.x = 0.0 SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ENDIF ELSE IF rappelData.vAttachPos.x > 0.0 rappelData.vAttachPos.x = 0.0 SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ENDIF ENDIF BREAK CASE RAPPEL_STATE_JUMPING_STATIC CASE RAPPEL_STATE_JUMPING_DOWN // when anim finished, go back to idle BOOL bResetToIdle bResetToIdle = FALSE IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_a") OR IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_jump_c") IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_jump_c") SET_ENTITY_ANIM_SPEED(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_jump_c", rappelData.fOverrideBigJumpSpeed) fAnimPhase = GET_ENTITY_ANIM_CURRENT_TIME(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_jump_c") IF DOES_ENTITY_EXIST(rappelData.pulleyObject) IF IS_ENTITY_PLAYING_ANIM(rappelData.pulleyObject, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_c_Prop") IF fAnimPhase >=0 AND fAnimPhase <= 1 SET_ENTITY_ANIM_CURRENT_TIME(rappelData.pulleyObject, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_c_Prop", fAnimPhase) SET_ENTITY_ANIM_SPEED(rappelData.pulleyObject, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_c_Prop", rappelData.fOverrideBigJumpSpeed) ENDIF ENDIF ENDIF IF NOT rappelData.bDisabledPainAudio IF rappelData.ped = PLAYER_PED_ID() IF NOT rappelData.bDoneLandGrunt IF fAnimPhase >= 0.82 IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF GET_RANDOM_INT_IN_RANGE(0,4) = 0 PLAY_PAIN(PLAYER_PED_ID(), AUD_DAMAGE_REASON_CLIMB_SMALL,0) ENDIF ENDIF rappelData.bDoneLandGrunt = TRUE ENDIF ENDIF ENDIF ENDIF ELIF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_a") SET_ENTITY_ANIM_SPEED(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_jump_a", rappelData.fOverrideSmallJumpSpeed) fAnimPhase = GET_ENTITY_ANIM_CURRENT_TIME(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_a") IF DOES_ENTITY_EXIST(rappelData.pulleyObject) IF IS_ENTITY_PLAYING_ANIM(rappelData.pulleyObject, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_A_Prop") IF fAnimPhase >=0 AND fAnimPhase <= 1 SET_ENTITY_ANIM_CURRENT_TIME(rappelData.pulleyObject, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_A_Prop", fAnimPhase) SET_ENTITY_ANIM_SPEED(rappelData.pulleyObject, GET_RAPPEL_ANIM_DICT_NAME(), "Rappel_Jump_A_Prop", rappelData.fOverrideSmallJumpSpeed) ENDIF ENDIF ENDIF IF NOT rappelData.bDisabledPainAudio IF rappelData.ped = PLAYER_PED_ID() IF NOT rappelData.bDoneLandGrunt IF fAnimPhase >= 0.740 IF GET_RANDOM_INT_IN_RANGE(0,4) = 0 PLAY_PAIN(PLAYER_PED_ID(), AUD_DAMAGE_REASON_CLIMB_SMALL,0) ENDIF rappelData.bDoneLandGrunt = TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ELSE IF GET_GAME_TIMER() >= rappelData.iJumpStartTime + 300 AND bAllowResetToIdle bResetToIdle = TRUE ENDIF ENDIF IF NOT bResetToIdle IF fAnimPhase >= 0.99 bResetToIdle = TRUE ELSE BOOL bControlPressed bControlPressed = FALSE IF (bIsAI AND rappelData.AI <> RAPPEL_AI_STOP) OR bForceSlowJumpDown bControlPressed = TRUE ELSE IF rappelData.bCurrentJumpIsBig IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_BIG_JUMP_CONTROL()) bControlPressed = TRUE ENDIF ELSE IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_NORMAL_JUMP_CONTROL()) OR (IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_BIG_JUMP_CONTROL()) AND rappelData.bSetBigJumpControlAsNormal) bControlPressed = TRUE ELSE IF rappelData.bForceSmallJumpOnBigJumpControl IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_BIG_JUMP_CONTROL()) bControlPressed = TRUE ENDIF ENDIF ENDIF ENDIF ENDIF IF bControlPressed AND fAnimPhase < MAX_STRENGTH_JUMP_PHASE AND NOT (bIsAI AND fAnimPhase > rappelData.fOverrideMaxJumpPhase) rappelData.fCurrentJumpStrength = fAnimPhase / MAX_STRENGTH_JUMP_PHASE IF rappelData.fCurrentJumpStrength > 1.0 rappelData.fCurrentJumpStrength = 1.0 ELIF rappelData.fCurrentJumpStrength < 0.0 rappelData.fCurrentJumpStrength = 0.0 ENDIF ELSE // calculate the final anim phase the jump will stop on IF rappelData.fStopDescendPhase < 0 IF bControlPressed AND NOT (bIsAI AND fAnimPhase > rappelData.fOverrideMaxJumpPhase) rappelData.fCurrentJumpStrength = 1.0 ENDIF //IF NOT bIsAI IF NOT rappelData.bCurrentJumpIsBig rappelData.fStopDescendPhase = MIN_STOP_DESCEND_PHASE + ((MAX_STOP_DESCEND_PHASE - MIN_STOP_DESCEND_PHASE) * rappelData.fCurrentJumpStrength) rappelData.fJumpDeceleration = JUMP_DOWN_MIN_DECELERATION_SMALL + ((JUMP_DOWN_MAX_DECELERATION_SMALL - JUMP_DOWN_MIN_DECELERATION_SMALL) * rappelData.fCurrentJumpStrength) ELSE rappelData.fStopDescendPhase = MIN_STOP_DESCEND_PHASE_BIG + ((MAX_STOP_DESCEND_PHASE_BIG - MIN_STOP_DESCEND_PHASE_BIG) * rappelData.fCurrentJumpStrength) rappelData.fJumpDeceleration = JUMP_DOWN_MIN_DECELERATION_BIG + ((JUMP_DOWN_MAX_DECELERATION_BIG - JUMP_DOWN_MIN_DECELERATION_BIG) * rappelData.fCurrentJumpStrength) ENDIF //PRINTSTRING("stop descend phase = ") PRINTFLOAT(rappelData.fStopDescendPhase) PRINTNL() //PRINTSTRING("decel = ") PRINTFLOAT(rappelData.fJumpDeceleration) PRINTNL() //ELSE // rappelData.fStopDescendPhase = fAnimPhase // IF NOT rappelData.bCurrentJumpIsBig /// rappelData.fJumpDeceleration = JUMP_DOWN_MAX_DECELERATION_SMALL // ELSE // rappelData.fJumpDeceleration = JUMP_DOWN_MAX_DECELERATION_BIG // ENDIF //ENDIF ENDIF ENDIF // set speed IF SHOULD_RAPPEL_JUMP_BE_MOVING(rappelData, fAnimPhase) IF fAnimPhase <= rappelData.fStopDescendPhase OR (bControlPressed AND rappelData.fStopDescendPhase < 0) IF rappelData.bCurrentJumpIsBig rappelData.fSpeed = rappelData.fSpeed +@ JUMP_DOWN_BIG_ACCELERATION ELSE rappelData.fSpeed = rappelData.fSpeed +@ JUMP_DOWN_ACCELERATION ENDIF ELSE rappelData.fSpeed = rappelData.fSpeed -@ rappelData.fJumpDeceleration ENDIF FLOAT fMaxSpeed IF NOT rappelData.bCurrentJumpIsBig IF fAnimPhase <= rappelData.fStopDescendPhase OR rappelData.fStopDescendPhase >= MAX_STOP_DESCEND_PHASE fMaxSpeed = JUMP_DOWN_SPEED_ACCELERATING ELSE fMaxSpeed = JUMP_DOWN_SPEED ENDIF ELSE fMaxSpeed = JUMP_DOWN_SPEED_BIG ENDIF IF rappelData.fSpeed > fMaxSpeed rappelData.fSpeed = fMaxSpeed ELIF rappelData.fSpeed < 0 rappelData.fSpeed = 0 ENDIF IF bForceSlowJumpDown rappelData.fSpeed /= 1.75 ENDIF ELSE rappelData.fSpeed = 0.0 ENDIF ENDIF ENDIF IF bResetToIdle SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ELSE // allow convert static jump into jumping down IF rappelData.state = RAPPEL_STATE_JUMPING_STATIC IF fAnimPhase <= ALLOW_JUMP_DOWN_CONVERT_PHASE IF bIsAI IF rappelData.ai = RAPPEL_AI_MOVE_FAST bDoRappelAction = TRUE ENDIF ELSE IF iLY > STICK_MOVEMENT_RAPPEL_DOWN bDoRappelAction = TRUE ENDIF ENDIF IF bDoRappelAction SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_JUMPING_DOWN, FALSE, FALSE, FALSE) //PLAY_RAPPEL_SOUND(rappelData, RAPPEL_SOUND_RAPPEL) ENDIF ENDIF ENDIF ENDIF //IF rappelData.ped = PLAYER_PED_ID() // printfloat(rappelData.fSpeed) printnl() //ENDIF BREAK CASE RAPPEL_STATE_SLIDING IF bIsAI IF rappelData.ai = RAPPEL_AI_MOVE_FAST bDoRappelAction = TRUE ENDIF ELSE bDoRappelAction = TRUE //IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_NORMAL_JUMP_CONTROL()) // bDoRappelAction = TRUE //ENDIF ENDIF IF HAS_FREE_ROPING_FINISHED(rappelData) bDoRappelAction = FALSE ENDIF IF bDoRappelAction IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_NORMAL_JUMP_CONTROL()) OR bIsAI rappelData.fSpeed = rappelData.fSpeed +@ SLIDE_ACCEL IF rappelData.fSpeed >= DEFAULT_MAX_FAST_SLIDE_SPEED rappelData.fSpeed = DEFAULT_MAX_FAST_SLIDE_SPEED ENDIF ELSE FLOAT fMaxSpeed fMaxSpeed = rappelData.fSpeed IF fMaxSpeed < rappelData.fMaxSlideSpeed fMaxSpeed = rappelData.fMaxSlideSpeed ENDIF rappelData.fSpeed = rappelData.fSpeed +@ SLIDE_ACCEL IF rappelData.fSpeed >= fMaxSpeed rappelData.fSpeed = fMaxSpeed ENDIF ENDIF ELSE rappelData.fSpeed = rappelData.fSpeed -@ SLIDE_DECEL IF rappelData.fSpeed <= 0.0 rappelData.fSpeed = 0.0 SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ENDIF ENDIF printfloat(rappelData.fSpeed) printnl() BREAK CASE RAPPEL_STATE_TRANSITION_TO_FREE_ROPING BOOL bGotoIdle bGotoIdle = FALSE IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_to_free_rope") fAnimPhase = GET_ENTITY_ANIM_CURRENT_TIME(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_to_free_rope") IF fAnimPhase <= 0.74 AND fAnimPhase >= 0.38 rappelData.fSpeed = rappelData.fSpeed +@ SLIDE_ACCEL * 2 IF rappelData.fSpeed >= rappelData.fMaxSlideSpeed rappelData.fSpeed = rappelData.fMaxSlideSpeed ENDIF ELSE rappelData.fSpeed = rappelData.fSpeed -@ SLIDE_DECEL IF rappelData.fSpeed <= 0.0 rappelData.fSpeed = 0.0 ENDIF ENDIF //printfloat(rappelData.fSpeed) printnl() IF fAnimPhase >= 0.98 bGotoIdle = TRUE ENDIF ELSE //bGotoIdle = TRUE ENDIF IF bGotoIdle rappelData.bFreeRoping = TRUE SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_IDLING) ENDIF BREAK CASE RAPPEL_STATE_DISMOUNT_FREE_ROPING BOOL bCancel bCancel = FALSE IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "land_action") IF GET_ENTITY_ANIM_CURRENT_TIME(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "land_action") >= 0.64 bCancel = TRUE ENDIF ELSE IF GET_GAME_TIMER() >= rappelData.iSetStateTime + 500 bCancel = TRUE ENDIF ENDIF IF bCancel CANCEL_RAPPEL(rappelData, FALSE, rappelData.dismountWeapon, TRUE, FALSE) rappelData.bUnpinnedForDismount = TRUE ENDIF BREAK ENDSWITCH bDoRappelAction = FALSE IF NOT rappelData.bFreeRoping BOOL bDoingBigJump = FALSE BOOL bDoingSideJump = FALSE // handle jump IF bIsAI IF rappelData.ai = RAPPEL_AI_MOVE_FAST bDoRappelAction = TRUE bDoingBigJump = rappelData.bAllowBigJumps ELIF rappelData.ai = RAPPEL_AI_SWING_LEFT OR rappelData.ai = RAPPEL_AI_SWING_RIGHT bDoRappelAction = TRUE bDoingSideJump = rappelData.bAllowSideJumps ENDIF ELSE IF IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, GET_NORMAL_JUMP_CONTROL()) OR (IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_BIG_JUMP_CONTROL()) AND rappelData.bSetBigJumpControlAsNormal) bDoRappelAction = TRUE ELIF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, GET_BIG_JUMP_CONTROL()) AND rappelData.bAllowBigJumps bDoRappelAction = TRUE bDoingBigJump = TRUE ENDIF ENDIF IF bDoRappelAction // jumping down BOOL bAllowJump = FALSE IF rappelData.state <= RAPPEL_STATE_WALKING bAllowJump = TRUE ELSE IF fAnimPhase > ALLOW_START_NEW_JUMP_PHASE IF bAllowRapidConvertJump bAllowJump = TRUE ENDIF ENDIF ENDIF IF bAllowJump IF iLY > STICK_MOVEMENT_RAPPEL_DOWN OR (bIsAI AND rappelData.ai = RAPPEL_AI_MOVE_FAST) OR bDoingBigJump OR bForceSlowJumpDown // do a small or big jump IF rappelData.bAllowSmallJumps OR bDoingBigJump rappelData.bCurrentJumpIsBig = bDoingBigJump IF rappelData.bForceSmallJumpOnBigJumpControl rappelData.bCurrentJumpIsBig = FALSE ENDIF SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_JUMPING_DOWN, FALSE, TRUE) ENDIF ELIF iLX > STICK_MOVEMENT_RAPPEL_SIDE OR iLX < -STICK_MOVEMENT_RAPPEL_SIDE OR bDoingSideJump // do a side jump IF rappelData.bAllowSideJumps SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_JUMPING_SIDEWAYS, FALSE, TRUE) IF iLX > 0 OR rappelData.ai = RAPPEL_AI_SWING_RIGHT rappelData.bCurrentSideJumpIsRight = TRUE rappelData.fSideJumpSpeed = 2.8 ELIF iLX < 0 OR rappelData.ai = RAPPEL_AI_SWING_LEFT rappelData.bCurrentSideJumpIsRight = FALSE rappelData.fSideJumpSpeed = -2.5 ENDIF ENDIF ELSE // do a static jump SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_JUMPING_STATIC, FALSE, TRUE) ENDIF ENDIF ENDIF ENDIF // move down by speed IF rappelData.vAttachPos.z > rappelData.fLimitZ IF rappelData.state <> RAPPEL_STATE_WALKING IF rappelData.vAttachPos.z <= (rappelData.fLimitZ + rappelData.fSlowDownByLimitRange) rappelData.fSpeed = rappelData.fSpeed -@ FAST_DECELERATION IF rappelData.fSpeed < 0 rappelData.fSpeed = 0 ENDIF ENDIF rappelData.vAttachPos.z = rappelData.vAttachPos.z -@ rappelData.fSpeed ELSE VECTOR vDisplace = GET_PED_EXTRACTED_DISPLACEMENT(rappelData.ped, FALSE) rappelData.vAttachPos.z += vDisplace.z ENDIF ENDIF // apply additional attach offset for free roping ped VECTOR vModAttach = <<0,0,0>> /* IF rappelData.bFreeRoping vModAttach.x = -0.0137329 vModAttach.y = -0.160645 ELSE vModAttach.x = -0.0141535 vModAttach.y = -0.385494 ENDIF */ FLOAT fConvertToFreeRopingPhase IF rappelData.bFreeRoping fConvertToFreeRopingPhase = 1.0 ELSE IF rappelData.state <> RAPPEL_STATE_TRANSITION_TO_FREE_ROPING fConvertToFreeRopingPhase = 0.0 ELSE IF IS_ENTITY_PLAYING_ANIM(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_to_free_rope") fConvertToFreeRopingPhase = GET_ENTITY_ANIM_CURRENT_TIME(rappelData.ped, GET_RAPPEL_ANIM_DICT_NAME(), "rappel_to_free_rope") ENDIF ENDIF ENDIF IF fConvertToFreeRopingPhase < 0 fConvertToFreeRopingPhase = 0 ENDIF vModAttach.x = -0.0141535 + (-0.0004206 * fConvertToFreeRopingPhase) vModAttach.y = -0.385494 + (0.224849 * fConvertToFreeRopingPhase) IF rappelData.state <> RAPPEL_STATE_DISMOUNT_FREE_ROPING ATTACH_ENTITY_TO_ENTITY(rappelData.ped, rappelData.anchorObject, 0, rappelData.vAttachPos + vModAttach, <<0,0,0>>, TRUE) ENDIF // do help text IF NOT bIsAI IF NOT rappelData.bShownHelp IF NOT rappelData.bFreeRoping PRINT_HELP("RAPPEL_HELP") ELSE PRINT_HELP("FREEROPE_HELP") ENDIF rappelData.bShownHelp = TRUE ENDIF ENDIF ELSE CANCEL_RAPPEL(rappelData) ENDIF ENDPROC // delete rappel rope PROC DELETE_RAPPEL_ROPE(RAPPEL_DATA &rappelData) IF rappelData.bRopeCreated IF DOES_ROPE_EXIST(rappelData.rope) DELETE_ROPE(rappelData.rope) ENDIF IF DOES_ENTITY_EXIST(rappelData.weightObject) DELETE_OBJECT(rappelData.weightObject) ENDIF IF DOES_ENTITY_EXIST(rappelData.pulleyObject) DELETE_OBJECT(rappelData.pulleyObject) ENDIF rappelData.bRopeCreated = FALSE ENDIF ENDPROC // fill rope properties PROC FILL_ROPE_PROPERTIES(RAPPEL_DATA &rappelData, FLOAT fLength) rappelData.iRopeVertexCount = GET_ROPE_VERTEX_COUNT(rappelData.rope) rappelData.iLastRopeVertex = 0 rappelData.iNextRopeVertex = rappelData.iLastRopeVertex + 1 rappelData.fLength = fLength rappelData.fRopeSegmentLength = fLength / (rappelData.iRopeVertexCount - 1) ENDPROC // create the rappel rope PROC CREATE_RAPPEL_ROPE(RAPPEL_DATA &rappelData, FLOAT fLength, BOOL b32Vertex = TRUE, BOOL bCreateAsUnfurled = TRUE, FLOAT fTimeMultiplier = DEFAULT_ROPE_WEIGHT, FLOAT fCreateRopeLength = -1.0) INT i DELETE_RAPPEL_ROPE(rappelData) IF DOES_ENTITY_EXIST(rappelData.anchorObject) PHYSICS_ROPE_TYPE ropeType IF b32Vertex ropeType = PHYSICS_ROPE_THIN_WIRE_32 ELSE ropeType = PHYSICS_ROPE_DEFAULT ENDIF FLOAT fRopeLength IF fCreateRopeLength < 0 fRopeLength = fLength ELSE fRopeLength = fCreateRopeLength ENDIF rappelData.rope = ADD_ROPE(GET_ENTITY_COORDS(rappelData.anchorObject), <<0.0, 90.0, 0.0>>, fRopeLength, ropeType, fRopeLength, 0.5, 0.5, TRUE, FALSE, TRUE, fTimeMultiplier) FILL_ROPE_PROPERTIES(rappelData, fLength) IF bCreateAsUnfurled REPEAT rappelData.iRopeVertexCount i PIN_ROPE_VERTEX(rappelData.rope, i, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(rappelData.anchorObject, <<0,0,-(rappelData.fRopeSegmentLength * i)>>)) ENDREPEAT rappelData.bUnfurling = FALSE ELSE VECTOR vPinOffset REPEAT rappelData.iRopeVertexCount i IF i=0 vPinOffset = <<0,0,0>> ELSE IF i%2 = 0 vPinOffset.x = 1 ELSE vPinOffset.x = -1 ENDIF vPinOffset.y = 0 vPinOffset.z = i * -0.02 ENDIF PIN_ROPE_VERTEX(rappelData.rope, i, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(rappelData.anchorObject, vPinOffset)) ENDREPEAT rappelData.bUnfurling = TRUE ENDIF rappelData.bAttachedWeight = FALSE rappelData.bAllowRopeMovement = FALSE rappelData.bRopeCreated = TRUE ENDIF ENDPROC // draw the rappel rope PROC HANDLE_RAPPEL_ROPE(RAPPEL_DATA &rappelData, BOOL bSwapHands = FALSE, BOOL bOverrideHand = FALSE, BOOL bInstantSnap = FALSE, BOOL bAfterDismount = FALSE) INT i IF DOES_ENTITY_EXIST(rappelData.anchorObject) IF NOT rappelData.bUnfurling IF rappelData.bAllowRopeMovement IF (bAfterDismount OR NOT IS_PED_INJURED(rappelData.ped)) AND NOT rappelData.bUnpinnedForDismount VECTOR vHand VECTOR vAnchor VECTOR vUnitVector VECTOR vPinVertex VECTOR vInterpolatedVertexPos FLOAT fAnchorToHandDist FLOAT fDistanceToNext FLOAT fRopeLengthToVertex IF NOT bAfterDismount PROCESS_ENTITY_ATTACHMENTS(rappelData.ped) ENDIF IF NOT rappelData.bOverrideRopeOrigin vAnchor = GET_ENTITY_COORDS(rappelData.anchorObject) ELSE vAnchor = rappelData.vOverrideRopeOrigin ENDIF IF NOT bAfterDismount IF rappelData.bFreeRoping vHand = GET_PED_BONE_COORDS(rappelData.ped, BONETAG_R_HAND, <>) ELSE PED_BONETAG handBone IF NOT bSwapHands handBone = BONETAG_PH_L_HAND ELSE handBone = BONETAG_PH_R_HAND ENDIF vHand = GET_PED_BONE_COORDS(rappelData.ped, handBone, <<0,0,0>>) ENDIF rappelData.vCacheHand = vHand ELSE vHand = rappelData.vCacheHand IF vHand.x < vAnchor.x vHand.x = vHand.x +@ 0.05 IF vHand.x > vAnchor.x vHand.x = vAnchor.x ENDIF ELIF vHand.x > vAnchor.x vHand.x = vHand.x -@ 0.05 IF vHand.x < vAnchor.x vHand.x = vAnchor.x ENDIF ENDIF IF vHand.y < vAnchor.y vHand.y = vHand.y +@ 0.05 IF vHand.y > vAnchor.y vHand.y = vAnchor.y ENDIF ELIF vHand.y > vAnchor.y vHand.y = vHand.y -@ 0.05 IF vHand.y < vAnchor.y vHand.y = vAnchor.y ENDIF ENDIF rappelData.vCacheHand = vHand ENDIF IF bOverrideHand vHand = rappelData.vOverrideHand ENDIF fAnchorToHandDist = GET_DISTANCE_BETWEEN_COORDS(vAnchor, vHand) // update current last vertex passed IF NOT bInstantSnap AND NOT bAfterDismount IF rappelData.iNextRopeVertex < (rappelData.iRopeVertexCount-1) fDistanceToNext = rappelData.fRopeSegmentLength * rappelData.iNextRopeVertex IF fAnchorToHandDist > fDistanceToNext rappelData.iLastRopeVertex++ rappelData.iNextRopevertex++ rappelData.bDirectlyPinNextVertex = FALSE ENDIF ENDIF ENDIF REPEAT rappelData.iRopeVertexCount i // pinning / unpinning IF i = 0 // pin top of rope to anchor PIN_ROPE_VERTEX(rappelData.rope, i, vAnchor) ELIF i <= rappelData.iNextRopeVertex + 1 fRopeLengthToVertex = rappelData.fRopeSegmentLength * i vUnitVector = (vHand - vAnchor) / fAnchorToHandDist vPinVertex = <> IF i <> rappelData.iNextRopeVertex + 1 OR rappelData.bDirectlyPinNextVertex OR bInstantSnap // direcly pin to desired point PIN_ROPE_VERTEX(rappelData.rope, i, vPinVertex) ELSE // otherwise interpolate nicely to avoid pop VECTOR vNextVertexPos = GET_ROPE_VERTEX_COORD(rappelData.rope, i) FLOAT fNextVertexDistanceToPin = GET_DISTANCE_BETWEEN_COORDS(vPinVertex, vNextVertexPos) IF fNextVertexDistanceToPin <= DIRECT_PIN_NEXT_VERTEX_DIST rappelData.bDirectlyPinNextVertex = TRUE PIN_ROPE_VERTEX(rappelData.rope, i, vPinVertex) ELSE FLOAT fRopeVertexInterpSpeed = fNextVertexDistanceToPin * 7.5 //PRINTSTRING("distance to pin = ") PRINTFLOAT(fNextVertexDistanceToPin) PRINTNL() //PRINTSTRING("interp speed = ") PRINTFLOAT(fRopeVertexInterpSpeed) PRINTNL() IF vPinVertex.x >= vNextVertexPos.x vInterpolatedVertexPos.x = vNextVertexPos.x +@ fRopeVertexInterpSpeed IF vInterpolatedVertexPos.x > vPinVertex.x vInterpolatedVertexPos.x = vPinVertex.x ENDIF ELIF vPinVertex.x <= vNextVertexPos.x vInterpolatedVertexPos.x = vNextVertexPos.x -@ fRopeVertexInterpSpeed IF vInterpolatedVertexPos.x < vPinVertex.x vInterpolatedVertexPos.x = vPinVertex.x ENDIF ENDIF IF vPinVertex.y >= vNextVertexPos.y vInterpolatedVertexPos.y = vNextVertexPos.y +@ fRopeVertexInterpSpeed IF vInterpolatedVertexPos.y > vPinVertex.y vInterpolatedVertexPos.y = vPinVertex.y ENDIF ELIF vPinVertex.y <= vNextVertexPos.y vInterpolatedVertexPos.y = vNextVertexPos.y -@ fRopeVertexInterpSpeed IF vInterpolatedVertexPos.y < vPinVertex.y vInterpolatedVertexPos.y = vPinVertex.y ENDIF ENDIF IF vPinVertex.z >= vNextVertexPos.z vInterpolatedVertexPos.z = vNextVertexPos.z +@ fRopeVertexInterpSpeed IF vInterpolatedVertexPos.z > vPinVertex.z vInterpolatedVertexPos.z = vPinVertex.z ENDIF ELIF vPinVertex.z <= vNextVertexPos.z vInterpolatedVertexPos.z = vNextVertexPos.z -@ fRopeVertexInterpSpeed IF vInterpolatedVertexPos.z < vPinVertex.z vInterpolatedVertexPos.z = vPinVertex.z ENDIF ENDIF PIN_ROPE_VERTEX(rappelData.rope, i, vInterpolatedVertexPos) ENDIF ENDIF ELSE IF NOT bInstantSnap AND NOT bAfterDismount // handle last vertex IF i=rappelData.iRopeVertexCount - 1 IF NOT rappelData.bPinnedLastVertex UNPIN_ROPE_VERTEX(rappelData.rope, i) IF GET_GAME_TIMER() >= rappelData.iLastVertexTime VECTOR vLastVertex = GET_ROPE_VERTEX_COORD(rappelData.rope, i) VECTOR vLastOffset = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(rappelData.ped, vLastVertex) CONST_FLOAT STOP_LAST_VERTEX_Y 0.68 IF vLastOffset.y > STOP_LAST_VERTEX_Y PIN_ROPE_VERTEX(rappelData.rope, i, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(rappelData.ped, <>)) rappelData.iLastVertexTime = GET_GAME_TIMER() + 50 rappelData.bPinnedLastVertex = TRUE ENDIF ENDIF ELSE IF GET_GAME_TIMER() >= rappelData.iLastVertexTime UNPIN_ROPE_VERTEX(rappelData.rope, i) rappelData.iLastVertexTime = GET_GAME_TIMER() + 1000 rappelData.bPinnedLastVertex = FALSE ENDIF ENDIF ELSE UNPIN_ROPE_VERTEX(rappelData.rope, i) ENDIF ENDIF ENDIF #IF IS_DEBUG_BUILD IF bDebugRappelInfo SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE) DRAW_DEBUG_SPHERE(GET_ROPE_VERTEX_COORD(rappelData.rope, i), 0.05) ENDIF #ENDIF ENDREPEAT ENDIF ELSE rappelData.bAllowRopeMovement = TRUE ENDIF ELSE IF NOT rappelData.bAllowRopeMovement UNPIN_ALL_ROPE_VERTICES_EXCEPT_ANCHOR(rappelData) rappelData.weightObject = CREATE_OBJECT_NO_OFFSET(GET_RAPPEL_ANCHOR_MODEL_NAME(), GET_ROPE_VERTEX_COORD(rappelData.rope, rappelData.iRopeVertexCount-1)) SET_ACTIVATE_OBJECT_PHYSICS_AS_SOON_AS_IT_IS_UNFROZEN(rappelData.weightObject, TRUE) SET_ENTITY_VISIBLE(rappelData.weightObject, FALSE) rappelData.bAllowRopeMovement = TRUE ELSE //REPEAT rappelData.iRopeVertexCount i // SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE) // DRAW_DEBUG_SPHERE(GET_ROPE_VERTEX_COORD(rappelData.rope, i), 0.1) //ENDREPEAT IF NOT rappelData.bAttachedWeight IF DOES_ENTITY_HAVE_PHYSICS(rappelData.weightObject) UNPIN_ROPE_VERTEX(rappelData.rope, 0) APPLY_FORCE_TO_ENTITY(rappelData.weightObject, APPLY_TYPE_EXTERNAL_IMPULSE, <<0,0,-1>>, <<0,0,0>>, 0, TRUE, TRUE, TRUE) //ATTACH_ROPE_TO_ENTITY(rappelData.rope, rappelData.weightObject, GET_ROPE_VERTEX_COORD(rappelData.rope, 0), 0) ATTACH_ENTITIES_TO_ROPE(rappelData.rope, rappelData.anchorObject, rappelData.weightObject, GET_ENTITY_COORDS(rappelData.anchorObject), GET_ENTITY_COORDS(rappelData.weightObject), rappelData.fLength, 0, 0) rappelData.bAttachedWeight = TRUE ENDIF ENDIF // check to see if can stop unfurling stage VECTOR vAnchorPos = GET_ENTITY_COORDS(rappelData.anchorObject) BOOL bCanStopUnfurling = TRUE FOR i=1 TO 5 CONST_FLOAT STOP_UNFURLING_DISTANCE_XY 1.0 CONST_FLOAT STOP_UNFURLING_DISTANCE_Z 0.7 VECTOR vVertexPos = GET_ROPE_VERTEX_COORD(rappelData.rope, i) IF vAnchorPos.z - vVertexPos.z <= (rappelData.fRopeSegmentLength * i * STOP_UNFURLING_DISTANCE_Z) bCanStopUnfurling = FALSE ELSE IF GET_DISTANCE_BETWEEN_COORDS(vAnchorPos, vVertexPos, FALSE) >= STOP_UNFURLING_DISTANCE_XY bCanStopUnfurling = FALSE ENDIF ENDIF ENDFOR IF bCanStopUnfurling rappelData.bUnfurling = FALSE ENDIF ENDIF ENDIF ENDIF ENDPROC // create anchor for rappel PROC CREATE_RAPPEL_ANCHOR(RAPPEL_DATA &rappelData, VEHICLE_INDEX attachVehicle, VECTOR vAnchorPos, VECTOR vAnchorRot) IF DOES_ENTITY_EXIST(rappelData.anchorObject) DELETE_OBJECT(rappelData.anchorObject) ENDIF rappelData.anchorObject = CREATE_OBJECT(GET_RAPPEL_ANCHOR_MODEL_NAME(), vAnchorPos) IF IS_VEHICLE_DRIVEABLE(attachVehicle) ATTACH_ENTITY_TO_ENTITY(rappelData.anchorObject, attachVehicle, 0, vAnchorPos, vAnchorRot) ELSE SET_ENTITY_ROTATION(rappelData.anchorObject, vAnchorRot) FREEZE_ENTITY_POSITION(rappelData.anchorObject, TRUE) ENDIF SET_ENTITY_VISIBLE(rappelData.anchorObject, FALSE) ENDPROC PROC CREATE_RAPPEL_PULLEY(RAPPEL_DATA &rappelData) IF DOES_ENTITY_EXIST(rappelData.pulleyObject) DELETE_OBJECT(rappelData.pulleyObject) ENDIF IF NOT IS_PED_INJURED(rappelData.ped) rappelData.pulleyObject = CREATE_OBJECT(GET_RAPPEL_PULLEY_MODEL_NAME(), GET_ENTITY_COORDS(rappelData.ped)) ATTACH_ENTITY_TO_ENTITY(rappelData.pulleyObject, rappelData.ped, GET_PED_BONE_INDEX(rappelData.ped, BONETAG_PH_L_HAND), <<0,0,0>>, <<0,0,0>>) ENDIF ENDPROC // set rappel AI PROC SET_RAPPEL_AI(RAPPEL_DATA &rappelData, RAPPEL_AI_ENUM setAI) rappelData.ai = setAI ENDPROC // set max free rope slide speed PROC SET_RAPPEL_MAX_SLIDE_SPEED(RAPPEL_DATA &rappelData, FLOAT fMaxSpeed) rappelData.fMaxSlideSpeed = fMaxSpeed ENDPROC // set rappel material PROC SET_RAPPEL_MATERIAL(RAPPEL_DATA &rappelData, RAPPEL_MATERIAL_ENUM setMaterial) rappelData.material = setMaterial ENDPROC // set allow small jumps PROC SET_RAPPEL_ALLOW_SMALL_JUMPS(RAPPEL_DATA &rappelData, BOOL bAllow) rappelData.bAllowSmallJumps = bAllow ENDPROC // set allow big jumps PROC SET_RAPPEL_ALLOW_BIG_JUMPS(RAPPEL_DATA &rappelData, BOOL bAllow) rappelData.bAllowBigJumps = bAllow ENDPROC // set force a small jump even if you hit the big jump button PROC SET_RAPPEL_FORCE_SMALL_JUMP_ON_BIG_JUMP_CONTROL(RAPPEL_DATA &rappelData, BOOL bForce) rappelData.bForceSmallJumpOnBigJumpControl = bForce ENDPROC // set allow side jumps PROC SET_RAPPEL_ALLOW_SIDE_JUMPS(RAPPEL_DATA &rappelData, BOOL bAllow) rappelData.bAllowSideJumps = bAllow ENDPROC // set big jump control as normal PROC SET_RAPPEL_BIG_JUMP_CONTROL_AS_NORMAL(RAPPEL_DATA &rappelData, BOOL bSet) rappelData.bSetBigJumpControlAsNormal = bSet ENDPROC // set to override rope origin PROC SET_RAPPEL_OVERRIDE_ROPE_ORIGIN(RAPPEL_DATA &rappelData, BOOL bOverride, VECTOR vOverridePos) rappelData.bOverrideRopeOrigin = bOverride IF bOverride rappelData.vOverrideRopeOrigin = vOverridePos ENDIF ENDPROC // set to override bResetRunFromFiresAndExplosionsFlagOnCancel PROC SET_RAPPEL_RESET_RUN_FROM_FIRES_AND_EXPLOSIONS_FLAG_ON_CANCEL(RAPPEL_DATA &rappelData, BOOL bReset) rappelData.bResetRunFromFiresAndExplosionsFlagOnCancel = bReset ENDPROC // set to override bResetDisableExplosionReactionsFlagOnCancel PROC SET_RAPPEL_RESET_DISABLE_EXPLOSIONS_FLAG_ON_CANCEL(RAPPEL_DATA &rappelData, BOOL bReset) rappelData.bResetDisableExplosionReactionsFlagOnCancel = bReset ENDPROC // setup sound ID PROC GET_RAPPEL_SOUND_ID(RAPPEL_DATA &rappelData) INT i REPEAT COUNT_OF(RAPPEL_SOUND_ENUM) i IF rappelData.iSoundID[i] = 0 rappelData.iSoundID[i] = GET_SOUND_ID() ENDIF ENDREPEAT ENDPROC // set rappel cam PROC DEFINE_RAPPEL_CAM_PROPERTIES(RAPPEL_DATA &rappelData, // PROPERTIES ROTATING AROUND PED TO VIEW LEFT/RIGHT FLOAT fCamDefaultHeading = 60.255, // default cam position x offset from ped FLOAT fCamYDist = -3.22, // default cam position y offset from ped FLOAT fCamXYInputToDegreesFactor = 1.2,//14.0, // amount stick movement is multiplied by when rotating around the ped - a higher value will make response more sensitive FLOAT fCamClockwiseLimit = 150.0, // amount in degrees the camera can be moved clockwise from its default heading (defined with xdist and ydist) FLOAT fCamAnticlockwiseLimit = 30.0, // amount in degrees the camera can be moved anticlockwise from its default heading (defined with xdist and ydist) FLOAT fCamXYSpeed = 0.4,//0.46, // speed the camera will travel at trying to snap back to its default view x/y // PROPERTIES ROTATING TO VIEW UP/DOWN FLOAT fCamZDist = 2.7, // default cam position z offset from ped FLOAT fCamZInputToHeightFactor = 0.02, // amount stick movement is multiplied by when panning z around the ped - a higher value will make response more sensitive FLOAT fCamZUpperLimit = 7.0, // distance above the ped the camera can be moved from its default pos FLOAT fCamZLowerLimit = -6.0, // distance below the ped the camera can be moved from its default pos FLOAT fCamZSpeed = 2.0, // meters per second the camera will travel at trying to snap back to its default view z // FOV FLOAT fCamFOV = 48.0) // camera fov rappelData.fCamDefaultHeading = fCamDefaultHeading rappelData.fCamYDist = fCamYDist rappelData.fCamXYInputToDegreesFactor = fCamXYInputToDegreesFactor rappelData.fCamClockwiseLimit = fCamClockwiseLimit rappelData.fCamAnticlockwiseLimit = fCamAnticlockwiseLimit rappelData.fCamXYSpeed = fCamXYSpeed rappelData.fCamZDist = fCamZDist rappelData.fCamZInputToHeightFactor = fCamZInputToHeightFactor rappelData.fCamZUpperLimit = fCamZUpperLimit rappelData.fCamZLowerLimit = fCamZLowerLimit rappelData.fCamZSpeed = fCamZSpeed rappelData.fCamFOV = fCamFOV IF DOES_CAM_EXIST(rappelData.cam) SET_CAM_FOV(rappelData.cam, rappelData.fCamFOV) ENDIF ENDPROC // Modify where the rappel cam points at PROC MODIFY_RAPPEL_CAM_POINT_AT(RAPPEL_DATA &rappelData, VECTOR vMod) rappelData.vModifyCamPointAt = vMod ENDPROC // initialise rappel PROC INIT_RAPPEL(RAPPEL_DATA &rappelData, VEHICLE_INDEX attachVehicle, VECTOR vAnchorPos, VECTOR vAnchorRot, FLOAT fStartZ, FLOAT fLimitZ, BOOL bSetupCamera = TRUE, BOOL bShowHelp = TRUE, BOOL bIsFreeRoping = FALSE, PED_INDEX ped = NULL, BOOL bPutAwayWeapon = FALSE, RAPPEL_STATE_ENUM initState = RAPPEL_STATE_IDLING, FLOAT fInitPhase = 0.0, BOOL bUsePulley = TRUE, BOOL bStartRenderingRappelCam = TRUE) IF NOT rappelData.bRappelling IF NOT DOES_ENTITY_EXIST(ped) rappelData.ped = PLAYER_PED_ID() ELSE rappelData.ped = ped ENDIF rappelData.ai = RAPPEL_AI_STOP rappelData.material = RAPPEL_MATERIAL_GLASS DEFINE_RAPPEL_CAM_PROPERTIES(rappelData) IF rappelData.ped = PLAYER_PED_ID() SET_PLAYER_CONTROL(PLAYER_ID(),FALSE) ELSE IF NOT IS_PED_INJURED(rappelData.ped) SET_PED_CONFIG_FLAG(rappelData.ped, PCF_RunFromFiresAndExplosions, FALSE) SET_PED_CONFIG_FLAG(rappelData.ped, PCF_DisableExplosionReactions, TRUE) rappelData.bResetRunFromFiresAndExplosionsFlagOnCancel = TRUE rappelData.bResetDisableExplosionReactionsFlagOnCancel = TRUE ENDIF ENDIF IF bUsePulley IF NOT bIsFreeRoping CREATE_RAPPEL_PULLEY(rappelData) ENDIF ENDIF CREATE_RAPPEL_ANCHOR(rappelData, attachVehicle, vAnchorPos, vAnchorRot) GET_RAPPEL_SOUND_ID(rappelData) rappelData.vAttachPos = <<0,0,fStartZ>> rappelData.fLimitZ = fLimitZ rappelData.bDirectlyPinNextVertex = FALSE rappelData.bSetupCam = FALSE rappelData.bShownHelp = FALSE IF NOT bShowHelp rappelData.bShownHelp = TRUE ENDIF rappelData.bFreeRoping = bIsFreeRoping rappelData.bAllowSmallJumps = TRUE rappelData.bAllowBigJumps = FALSE rappelData.bAllowSideJumps = FALSE rappelData.bForceSmallJumpOnBigJumpControl = FALSE rappelData.bPinnedLastVertex = FALSE rappelData.bUnpinnedForDismount = FALSE rappelData.fMaxSlideSpeed = DEFAULT_MAX_SLIDE_SPEED rappelData.fOverrideMaxJumpPhase = 1.0 rappelData.fOverrideBigJumpSpeed = DEFAULT_BIG_JUMP_SPEED rappelData.fOverrideSmallJumpSpeed = DEFAULT_SMALL_JUMP_SPEED IF bPutAwayWeapon SET_CURRENT_PED_WEAPON(rappelData.ped, WEAPONTYPE_UNARMED, TRUE) ENDIF SET_RAPPEL_STATE(rappelData, initState, TRUE, FALSE, TRUE, fInitPhase) HANDLE_RAPPEL_PED(rappelData, TRUE, FALSE) IF bSetupCamera //IF rappelData.ped = PLAYER_PED_ID() // init camera position rappelData.fTargetCamHeading = 0 rappelData.fCurrentCamHeading = rappelData.fTargetCamHeading rappelData.fTargetCamHeight = 0 rappelData.fCamZMod = 0 DO_RAPPEL_CAM(rappelData, FALSE, 0, 0, FALSE, -1000, bStartRenderingRappelCam) //ENDIF ENDIF rappelData.bRappelling = TRUE ENDIF ENDPROC // init rappel and create a rope PROC INIT_RAPPEL_WITH_ROPE(RAPPEL_DATA &rappelData, VEHICLE_INDEX attachVehicle, VECTOR vAnchorPos, VECTOR vAnchorRot, FLOAT fStartZ, FLOAT fLimitZ, FLOAT fRopeLength, BOOL bSetupCamera, BOOL bShowHelp = TRUE, BOOL bIsFreeRoping = FALSE, PED_INDEX ped = NULL, BOOL bCreateAsUnfurled = TRUE, BOOL bPutAwayWeapon = FALSE, FLOAT fRopeWeight = DEFAULT_ROPE_WEIGHT, FLOAT fCreateRopeLength = -1.0, BOOL bStartRenderingRappelCam = TRUE, RAPPEL_STATE_ENUM initState = RAPPEL_STATE_IDLING, FLOAT fInitPhase = 0.0) INIT_RAPPEL(rappelData, attachVehicle, vAnchorPos, vAnchorRot, fStartZ, fLimitZ, bSetupCamera, bShowHelp, bIsFreeRoping, ped, bPutAwayWeapon, initState, fInitPhase, TRUE, bStartRenderingRappelCam) CREATE_RAPPEL_ROPE(rappelData, fRopeLength, TRUE, bCreateAsUnfurled, fRopeWeight, fCreateRopeLength) ENDPROC // handle rappel player and rope PROC HANDLE_RAPPEL(RAPPEL_DATA &rappelData, BOOL bIsAI = FALSE, BOOL bDoCam = TRUE) HANDLE_RAPPEL_PED(rappelData, bIsAI, bDoCam) HANDLE_RAPPEL_ROPE(rappelData) ENDPROC // dismount rappel PROC DISMOUNT_RAPPEL(RAPPEL_DATA &rappelData, WEAPON_TYPE dismountWeapon = WEAPONTYPE_UNARMED) rappelData.dismountWeapon = dismountWeapon SET_RAPPEL_STATE(rappelData, RAPPEL_STATE_DISMOUNT_FREE_ROPING) ENDPROC /* // has the rappel sound finished? FUNC BOOL HAS_RAPPEL_SOUND_FINISHED(RAPPEL_DATA rappelData) INT i BOOL bFinished = TRUE REPEAT COUNT_OF(RAPPEL_SOUND_ENUM) i IF bFinished IF rappelData.iSoundID[i] <> 0 bFinished = HAS_SOUND_FINISHED(rappelData.iSoundID[i]) ENDIF ENDIF ENDREPEAT RETURN bFinished ENDFUNC */ // cleanup rappel - to ensure all assets are properly disposed of for mission cleanup PROC CLEANUP_RAPPEL(RAPPEL_DATA &rappelData) IF DOES_ENTITY_EXIST(rappelData.weightObject) DELETE_OBJECT(rappelData.weightObject) ENDIF CANCEL_RAPPEL(rappelData) DELETE_RAPPEL_ROPE(rappelData) IF DOES_ENTITY_EXIST(rappelData.anchorObject) DELETE_OBJECT(rappelData.anchorObject) ENDIF IF DOES_ENTITY_EXIST(rappelData.pulleyObject) DELETE_OBJECT(rappelData.pulleyObject) ENDIF //RELEASE_RAPPEL_AUDIO(rappelData) ENDPROC