2117 lines
71 KiB
Scheme
Executable File
2117 lines
71 KiB
Scheme
Executable File
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// 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 = <<vCurrentCamPos.x - vPedCoordsWithOffset.x, vCurrentCamPos.y - vPedCoordsWithOffset.y,rappelData.fCurrentCamHeight>>
|
|
//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, <<FREE_ROPE_HAND_OFFSET_X, FREE_ROPE_HAND_OFFSET_Y, 0>>)
|
|
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 = <<vAnchor.x + (fRopeLengthToVertex * vUnitVector.x), vAnchor.y + (fRopeLengthToVertex * vUnitVector.y), vAnchor.z + (fRopeLengthToVertex * vUnitVector.z)>>
|
|
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, <<vLastOffset.x, STOP_LAST_VERTEX_Y, vLastOffset.z>>))
|
|
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
|
|
|