3964 lines
124 KiB
Scheme
Executable File
3964 lines
124 KiB
Scheme
Executable File
USING "commands_itemsets.sch"
|
|
USING "script_blips.sch"
|
|
USING "RC_Helper_Functions.sch"
|
|
USING "Shared_Hud_Displays.sch"
|
|
USING "RC_Area_public.sch"
|
|
USING "rc_threat_public.sch"
|
|
USING "commands_pad.sch"
|
|
USING "LauncherInclude.sch"
|
|
USING "rgeneral_include.sch"
|
|
USING "minigame_midsized_message.sch"
|
|
USING "script_usecontext.sch"
|
|
USING "website_public.sch"
|
|
USING "mp_globals_block_SC_LB.sch"
|
|
|
|
// ======================================
|
|
// ENUMS
|
|
// ======================================
|
|
|
|
ENUM ELK_STATE
|
|
ES_NULL = 0,
|
|
|
|
// STATES WE NEED.
|
|
ES_CHECK_CAN_SPAWN,
|
|
ES_SPAWN_IN,
|
|
|
|
|
|
ES_START_GRAZE, // Here we start the animation, and flag a time.
|
|
ES_GRAZE,
|
|
ES_PAUSE_THEN_PICK_NEW_DESTINATION,
|
|
ES_CHOOSE_NEXT_DESTINATION,
|
|
ES_TRAVEL_TO_NEXT_DESTINATION,
|
|
ES_PAUSE_THEN_GRAZE,
|
|
|
|
ES_TRAVEL_THEN_ENTER_GRAZE_AND_WAIT_TO_DIE,
|
|
ES_ENTER_GRAZE_AND_WAIT_TO_DIE,
|
|
ES_GRAZE_AND_WAIT_TO_DIE,
|
|
ES_EXIT_GRAZE_AND_WAIT_TO_DIE,
|
|
ES_IDLE_AND_WAIT_TO_DIE,
|
|
|
|
ES_RUN_OFF,
|
|
ES_RUNNING_OFF,
|
|
ES_CLEAN_UP
|
|
ENDENUM
|
|
|
|
ENUM SPOOKED_REASON
|
|
SR_NULL = 0,
|
|
SR_SAW_PLAYER,
|
|
SR_HEARD_PLAYER,
|
|
SR_SMELLED_PLAYER,
|
|
SR_SPOOKED_BY_ELK,
|
|
SR_NEAR_MISS
|
|
ENDENUM
|
|
|
|
ENUM HIT_LOCATION
|
|
HL_NULL = 0,
|
|
HL_HEAD,
|
|
HL_NECK,
|
|
HL_HEART,
|
|
HL_FORELEG,
|
|
HL_BODY,
|
|
HL_ASS,
|
|
HL_HINDLEG,
|
|
|
|
NUM_HIT_LOCATIONS
|
|
ENDENUM
|
|
|
|
// ======================================
|
|
// Constants
|
|
// ======================================
|
|
|
|
CONST_INT MAX_HUNT_MODES 4 // Ambient hunt modes
|
|
CONST_INT MAX_ELKS 8 // HOW MANY ARE THERE IN THE POOL Needs to be defined before common hunting
|
|
CONST_INT MAX_GRAZE_AREAS 58 // WAYPOINTS FOR THE ELK TO WANDER ABOUT WITH
|
|
CONST_INT MAX_POLY_TEST_VERTS 8
|
|
CONST_INT MIN_ELK_GRAZE_TIME 15000
|
|
CONST_INT MAX_ELK_GRAZE_TIME 25000
|
|
CONST_INT MIN_ELK_WAIT_TIME 1500
|
|
CONST_INT MAX_ELK_WAIT_TIME 3000
|
|
|
|
CONST_FLOAT CALL_RANGE 200.0 // EFFECTIVE RANGE OF CALLING (TRIANGLE/Y) WHICH INCREASES THE ELKS BLIP ALPHA
|
|
CONST_INT MIN_BLIP_ALPHA 0 // 50 // DEFAULT = 0 // THE MINIMUM ALPHA OF THE BLIP. SET THIS HIGHER FOR DEBUG PURPOSES
|
|
|
|
CONST_FLOAT MIN_SAFE_SPAWN_DIST 30.0
|
|
CONST_FLOAT MAX_SAFE_SPAWN_DIST 125.0
|
|
|
|
//These variables are used to detect if the player has been detected by
|
|
//the elk. Used in CHECK_ELK_SPOOKED(int i) Will eventually need changing to use the
|
|
//AI perception system.
|
|
CONST_FLOAT ELK_SCENT_RANGE 45.0
|
|
CONST_FLOAT ELK_SCENT_WIDTH 10.0
|
|
CONST_FLOAT ELK_CLEANUP_DISTANCE 250.0
|
|
CONST_FLOAT SIGHT_RANGE_STANDING 30.0
|
|
CONST_FLOAT SIGHT_RANGE_DUCKED 20.0
|
|
CONST_FLOAT HEAR_RANGE 10.0
|
|
CONST_FLOAT ELK_FOV 90.0
|
|
|
|
// Used in Hunting2
|
|
CONST_INT iSAW_PLAYER_FLAG 0
|
|
CONST_INT iHEARD_PLAYER_FLAG 1
|
|
CONST_INT iSMELT_PLAYER_FLAG 2
|
|
CONST_INT iNEAR_MISS_FLAG 3
|
|
CONST_INT iSAW_SPOOKED_ELK_FLAG 4
|
|
|
|
CONST_INT FIVE_MINUTES 60000 * 5
|
|
CONST_INT THREE_MINUTES 60000 * 3
|
|
CONST_FLOAT CLOSE_KILL_RANGE 25.0
|
|
|
|
CONST_INT SCORE_HEART_SHOT 10
|
|
CONST_INT SCORE_HEAD_SHOT 5
|
|
CONST_INT SCORE_NECK_SHOT 7
|
|
CONST_INT SCORE_TORSO_SHOT 4
|
|
CONST_INT SCORE_ASS_SHOT 2
|
|
CONST_INT SCORE_LEG_SHOT 1
|
|
|
|
CONST_INT SCORE_SPOOKED_SHOT 1
|
|
CONST_INT SCORE_DOE 0
|
|
CONST_INT SCORE_UNKNOWN 2
|
|
|
|
CONST_INT SCORE_ROAD_KILL 1
|
|
CONST_INT SCORE_MOUNTAIN_LION_KILL 5
|
|
CONST_INT SCORE_BOAR_KILL 3
|
|
CONST_INT SCORE_COYOTE_KILL 2
|
|
CONST_INT SCORE_BIRD_KILL 5
|
|
CONST_INT SCORE_HUMAN_KILL 5
|
|
|
|
CONST_FLOAT k_ELK_SPOOK_RANGE 8.25
|
|
CONST_FLOAT k_ELK_SPOOK_RANGE_MULT 4.0
|
|
|
|
ENUM KILL_TYPE
|
|
KILL_UNKNOWN = -1,
|
|
KILL_HEART_SHOT,
|
|
KILL_HEAD_SHOT,
|
|
KILL_NECK_SHOT,
|
|
KILL_TORSO_SHOT,
|
|
KILL_ASS_SHOT,
|
|
KILL_LEG_SHOT,
|
|
KILL_SPOOKED_SHOT,
|
|
KILL_DOE_KILL,
|
|
KILL_MOUNTAIN_LION_KILL,
|
|
KILL_BOAR_KILL,
|
|
KILL_COYOTE_KILL,
|
|
KILL_BIRD_KILL,
|
|
KILL_HUMAN_KILL,
|
|
KILL_ROAD_KILL,
|
|
KILL_LIVE_ANIMAL,
|
|
KILL_NO_KILL
|
|
ENDENUM
|
|
|
|
CONST_INT MONEY_HEART_SHOT 100
|
|
CONST_INT MONEY_HEAD_SHOT 50
|
|
CONST_INT MONEY_NECK_SHOT 75
|
|
CONST_INT MONEY_TORSO_SHOT 50
|
|
CONST_INT MONEY_ASS_SHOT 50
|
|
CONST_INT MONEY_LEG_SHOT 50
|
|
CONST_INT MONEY_SPOOKED_SHOT 50
|
|
CONST_INT MONEY_DOE 25
|
|
CONST_INT MONEY_ROAD_KILL 5
|
|
CONST_INT MONEY_MOUNTAIN_LION_KILL 25
|
|
CONST_INT MONEY_BOAR_KILL 50
|
|
CONST_INT MONEY_COYOTE_KILL 10
|
|
CONST_INT MONEY_BIRD_KILL 10
|
|
CONST_INT MONEY_HUMAN_KILL 0
|
|
|
|
CONST_FLOAT MONEY_MULT_SNIPER 1.0
|
|
CONST_FLOAT MONEY_MULT_MELEE 0.5
|
|
CONST_FLOAT MONEY_MULT_PISTOL 1.0
|
|
CONST_FLOAT MONEY_MULT_SMG 0.75
|
|
CONST_FLOAT MONEY_MULT_RIFLE 1.0
|
|
CONST_FLOAT MONEY_MULT_MG 0.25
|
|
CONST_FLOAT MONEY_MULT_SHOTGUN 0.25
|
|
CONST_FLOAT MONEY_MULT_HEAVY 0.1
|
|
CONST_FLOAT MONEY_MULT_THROWN 0.1
|
|
|
|
|
|
CONST_INT MAX_ELK_PER_HERD 3
|
|
CONST_INT HERD_MEMBER_INDEX_START 3
|
|
CONST_INT HERD_MEMBER_LEFT 3
|
|
CONST_INT HERD_MEMBER_RIGHT 4
|
|
CONST_INT HERD_MEMBER_FRONT 5
|
|
CONST_INT HERD_MEMBER_REAR 6
|
|
|
|
CONST_INT PERCENTAGE_HERD_CHANCE 100 // Percentage chance this elk will form a herd.
|
|
CONST_INT PERCENTAGE_HERD_MEMBER_CHANCE 50 // Percentage chance a particular herd member will spawn.
|
|
|
|
//TWEAK_FLOAT WIND_METER_X 0.025
|
|
//TWEAK_FLOAT WIND_METER_Y -0.064
|
|
|
|
CONST_INT BLEAT_TRIGGER_MIN_DELAY 30000
|
|
CONST_INT BLEAT_TRIGGER_MAX_DELAY 60000
|
|
CONST_INT BLEAT_RESPONSE_DELAY 4000
|
|
|
|
CONST_INT MAX_DOE_IN_PLAY 3
|
|
|
|
CONST_INT MIN_DIALOGUE_DELAY_TIME 30000
|
|
CONST_INT MAX_DIALOGUE_DELAY_TIME 120000
|
|
|
|
CONST_INT CHALLENGE_DISPLAY_DELAY 1750
|
|
|
|
TWEAK_FLOAT CHALLENGE_BACK_X 0.05
|
|
TWEAK_FLOAT CHALLENGE_BACK_Y 0.30
|
|
TWEAK_FLOAT CHALLENGE_BACK_WIDTH 0.25
|
|
TWEAK_FLOAT CHALLENGE_BACK_HEIGHT 0.30
|
|
|
|
TWEAK_FLOAT CHALLENGE_TEXT_OFFSET_X 0.015
|
|
TWEAK_FLOAT CHALLENGE_TEXT_OFFSET_Y 0.015
|
|
TWEAK_FLOAT CHALLENGE_TEXT_TABBED_OFFSET_X 0.01
|
|
TWEAK_FLOAT CHALLENGE_TEXT_GOAL_BUFFER_Y 0.02
|
|
TWEAK_FLOAT CHALLENGE_TEXT_OBJ_BUFFER_Y 0.03
|
|
|
|
|
|
|
|
REL_GROUP_HASH mElkGroup
|
|
|
|
// =====================
|
|
// STRUCTS
|
|
// =====================
|
|
STRUCT MY_ELK
|
|
PED_INDEX mPed
|
|
BLIP_INDEX mElkBlip
|
|
|
|
INT iNextTestTime = 0
|
|
|
|
INT iBlipAlpha = 0
|
|
INT iCallTime = 0
|
|
INT iStartFadeTime = 0
|
|
INT iCallResponseTime = 0
|
|
|
|
BOOL bMustReplyToCall = FALSE
|
|
BOOL bRandomlyCalls = TRUE
|
|
BOOL bIsSpooked = FALSE
|
|
BOOL bCalling = FALSE
|
|
BOOL bCanFadeBlip = TRUE
|
|
BOOL bHardBlipped = FALSE
|
|
|
|
BOOL bBlockSpookedBlip = FALSE
|
|
|
|
SPOOKED_REASON eSpookedReason
|
|
|
|
MODEL_NAMES mModel = A_C_DEER
|
|
ELK_STATE elkState
|
|
|
|
//Elks spawn pos and scent offset position
|
|
VECTOR vPos
|
|
VECTOR vScentOffsetPos
|
|
|
|
//Waiting time at each node
|
|
INT iWaitTime
|
|
INT iGrazeTime
|
|
|
|
// ROUTE NODES
|
|
INT iCurNode
|
|
INT iPrevNode
|
|
INT iDestNode
|
|
|
|
BOOL bIsHerdLeader = FALSE
|
|
BOOL bIsHerdMember = FALSE
|
|
INT iLeaderIdx = -1
|
|
INt iNumFollowers = 0
|
|
|
|
FLOAT fRandHead
|
|
FLOAT fDist
|
|
|
|
INT iSpawnDelayTime
|
|
BOOL bDelayBeforeRespawn = FALSE
|
|
ENDSTRUCT
|
|
|
|
MY_ELK mElk[MAX_ELKS]
|
|
INT m_iTargetElk // Used when failing the mission, stores the index of the elk we were hunting at the time.
|
|
|
|
STRUCT ELK_SPAWN_LOCATION
|
|
VECTOR vCoord // A location an elk can spawn
|
|
BOOL bIsBooked = FALSE // Is this graze point booked to spawn an elk or is an elk going to the graze point
|
|
INT iNextSpawnTime = 0 // Next allowable spawn time.
|
|
ENDSTRUCT
|
|
|
|
CONST_INT ELK_SPAWN_RESPAWN_DELAY 40000 // A spawn pos needs to wait 30 seconds before something can spawn there again.
|
|
ELK_SPAWN_LOCATION elkSpawn[MAX_GRAZE_AREAS]
|
|
|
|
ENUM HUNTING_CHALLENGE
|
|
HC_INVALID = -1,
|
|
HC_MASTER_HUNTER,
|
|
HC_PHOTOJOURNALIST,
|
|
HC_WEAPONS_MASTER
|
|
ENDENUM
|
|
|
|
ENUM HUNTING_CHALLENGE_RANK
|
|
HCR_LOCKED = -1,
|
|
HCR_RANK_1,
|
|
HCR_RANK_2,
|
|
HCR_RANK_3,
|
|
HCR_RANK_4,
|
|
HCR_RANK_5,
|
|
HCR_COMPLETE
|
|
ENDENUM
|
|
|
|
ENUM HUNTING_CHALLENGE_STATUS
|
|
HCS_RANK_INIT,
|
|
HCS_RANK_UPDATE,
|
|
HCS_RANK_COMPLETE_TOAST,
|
|
HCS_RANK_NEXT
|
|
ENDENUM
|
|
|
|
STRUCT HUNTING_CHALLENGE_DATA
|
|
HUNTING_CHALLENGE_RANK hcRank
|
|
HUNTING_CHALLENGE_STATUS hcStatus
|
|
INT iPrevProgress
|
|
ENDSTRUCT
|
|
|
|
ENUM CORPSES_STATE
|
|
CS_UPDATE = 0,
|
|
CS_TAKING_PHOTO,
|
|
CS_POST_PHOTO,
|
|
CS_CONTACT_LIST,
|
|
CS_WAIT_MSG,
|
|
CS_WAIT_MSG_WRONG,
|
|
CS_WAIT_MSG_WRONG_POST,
|
|
CS_DO_SCORE_AND_CHALLENGES
|
|
ENDENUM
|
|
|
|
STRUCT HT_PLAYER_DATA
|
|
|
|
STRING sFailReason
|
|
INT iKillCount = 0
|
|
INT iHighScore
|
|
INT iScoreForBronze
|
|
INT iScoreForSilver
|
|
INT iScoreForGold
|
|
INT iScore = 0
|
|
INT iMoney = 0
|
|
BOOL bGivenMoney = FALSE
|
|
INT iHitsOnLocation[NUM_HIT_LOCATIONS]
|
|
|
|
BOOL bRunPlayerDeath = FALSE
|
|
|
|
//BOOL bCanDisplayChallengeToast = TRUE
|
|
HUNTING_CHALLENGE_DATA challengeData[COUNT_OF(HUNTING_CHALLENGE)]
|
|
structTimer unlockTimer
|
|
|
|
// Things needed for challenges
|
|
INT iKillsSinceSpooked
|
|
INT iKillStreakHeartshot
|
|
INT iKillsSinceElkCall
|
|
INT iKillsTimed
|
|
INT iKillsTimeRemaining
|
|
INT iKillTimes[10] // Using 10 for right now
|
|
INT iChallengeDisplayTime = -1
|
|
TIMEOFDAY todHuntStarted = INVALID_TIMEOFDAY
|
|
|
|
// Tracking.
|
|
INT iPhotosSent = 0
|
|
INT iCougarKills = 0
|
|
INT iBoarKills = 0
|
|
INT iCoyoteKills = 0
|
|
|
|
INT iLastCommentTime = 0
|
|
structTimer tTimeSpentHunting
|
|
|
|
// Leaderboard time is tracked in MS. To get that, multiply this timer by 1000, if bGoldAchieved is set to TRUE.
|
|
// For some reason, when passing in time to the leaderboard, you have to make it negative. This is so lower times show up on the top of the
|
|
// leaderboard. Ask Asa if this is confusing.
|
|
structTimer tTimeToGold
|
|
BOOL bGoldAchieved = FALSE
|
|
|
|
// Timing structs for speed challenge
|
|
// SIMPLE_USE_CONTEXT controlsUI
|
|
BOOL bSetupHuntingControls = FALSE
|
|
SCRIPT_SHARD_BIG_MESSAGE splashUI
|
|
BOOL bChallengeScreenSetup
|
|
END_SCREEN_DATASET challengeScreen
|
|
|
|
ITEMSET_INDEX setCorpses
|
|
ITEMSET_INDEX setPhoto
|
|
CORPSES_STATE eCorpseState
|
|
structTimer textTimer
|
|
BOOL bNearCorpse
|
|
BOOL bSentPhotoHelp
|
|
BOOL bSentPhotoNearHelp
|
|
BOOL bSentPhotoSendHelp
|
|
BOOL bSentUnlockText
|
|
BOOL bSentChalUnlockHelp
|
|
BOOL bSentDownwindHelp
|
|
BOOL bSentLowPointPerKillText
|
|
BOOL bSentNearBronzeText
|
|
BOOL bSentNearSilverText
|
|
BOOL bSentNearGoldText
|
|
|
|
BOOL bNeedLoserSound = FALSE
|
|
|
|
VEHICLE_INDEX vehQuad
|
|
|
|
WEAPON_GROUP lastWeaponUsed
|
|
FLOAT fLastCamZoom
|
|
BOOL bSetupDeath
|
|
|
|
INT iLastPhotoTime
|
|
|
|
SC_LEADERBOARD_CONTROL_STRUCT huntLB_control
|
|
SCALEFORM_INDEX huntLB_UI
|
|
|
|
BOOL bOnlineForPrediction
|
|
ENDSTRUCT
|
|
|
|
CONST_INT HUNTING_COMMENT_DELAY 8000
|
|
CONST_INT HUNTING_PHOTO_CATCH_DELAY 3000
|
|
HT_PLAYER_DATA Player_Hunt_Data
|
|
|
|
// =================================
|
|
// Variables
|
|
// =================================
|
|
|
|
// WIND
|
|
FLOAT fWindDirection
|
|
VECTOR vWindDirection
|
|
BOOL bIsAmbient = FALSE
|
|
|
|
CONST_FLOAT DISTANCE_HARD_BLIP_THRESHOLD 40.0
|
|
|
|
//Dealing with the players rifle
|
|
FLOAT fDistanceThreshold
|
|
FLOAT fZoomLevel = 1.0
|
|
BOOL bHadSniperRifle = FALSE
|
|
BOOL bHadSuppressor = FALSE
|
|
INT iSniperAmmoBefore = 0
|
|
BOOL bAllowCall = FALSE //Used to delay the player being able to use the elk whistle, Defined in here but only changed via a main hunting script
|
|
BOOL bPlayerCalling = FALSE
|
|
VECTOR vHuntingPlayerCoords
|
|
BOOL bPlayerKillElkIncorrectly = FALSE
|
|
BOOL bIsPlayerOutsideHuntArea = FALSE //Defined in here but only changed via a main hunting script
|
|
BOOL bSniperEquiped = FALSE //Defined in here but only changed via a main hunting script
|
|
BLIP_INDEX mCentreBlip
|
|
|
|
// ELK
|
|
INT iDoeInPlay = 0
|
|
INT iElksInPlay = 0
|
|
VECTOR SCENT_RANGE = << 0.0, 40.0, 0.0 >>
|
|
INT iRandGraze
|
|
BOOL bRandomBleat = FALSE
|
|
INT iBleatInitiateTime = 0
|
|
INT iBleatResponseTime = 0
|
|
INT iInitiatorIndex = -1
|
|
|
|
INT iElkTesting = -1
|
|
SHAPETEST_INDEX elkShapeTest
|
|
|
|
// SOUNDS
|
|
INT iSoundId = -1
|
|
INT iSoundDelay = 0
|
|
FLOAT fConcentration = 0.0
|
|
FLOAT fHeartBeat = 0.0
|
|
|
|
// KILLS
|
|
BOOL bUncleanKill = FALSE
|
|
INT iUncleanKills = 0
|
|
INT iLocalKillCount = 0
|
|
INT iMissMessageDelay = 0
|
|
CONST_INT MISS_MESSAGE_DELAY_TIME 500
|
|
BOOL bGotNearMissTime = FALSE
|
|
BOOL bSuppressNearMissMessage = FALSE
|
|
BOOL bShouldClearSuppressNearMissMsg = FALSE
|
|
CONST_INT SPAWN_DELAY_TIME 1000
|
|
|
|
// AREA
|
|
TEST_POLY mAreaCheck1
|
|
TEST_POLY mAreaCheck2
|
|
|
|
// TRAFFIC
|
|
FLOAT fCarDensity = 1.0
|
|
INT iDialDownTime = 0
|
|
BOOL bGotDialDownTime = FALSE
|
|
|
|
// HUD
|
|
BOOL bPauseTimer = FALSE
|
|
|
|
// TIMER
|
|
INT iEndTime = 0
|
|
INT iPauseDuration = 0
|
|
INT iPauseStartTime = 0
|
|
INT iPauseEndTime = 0
|
|
BOOL bGotPauseTime = FALSE
|
|
|
|
|
|
// ======================================
|
|
// COMMON FUNCTIONS
|
|
// ======================================
|
|
|
|
/// PURPOSE:
|
|
/// Checks to see if an animal ped was a doe.
|
|
/// RETURNS:
|
|
FUNC BOOL IS_ELK_A_DOE(ENTITY_INDEX entElk)
|
|
IF DOES_ENTITY_EXIST(entElk)
|
|
IF DECOR_EXIST_ON(entElk, "doe_elk")
|
|
RETURN DECOR_GET_BOOL(entElk, "doe_elk")
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
FUNC STRING GET_DISPLAY_NAME_FOR_KILL_TYPE(ENTITY_INDEX entCorpse, KILL_TYPE eKillType)
|
|
SWITCH eKillType
|
|
CASE KILL_HEART_SHOT RETURN "Elk (Heart)"
|
|
CASE KILL_HEAD_SHOT RETURN "Elk (Head)"
|
|
CASE KILL_NECK_SHOT RETURN "Elk (Neck)"
|
|
CASE KILL_TORSO_SHOT RETURN "Elk (Body)"
|
|
CASE KILL_ASS_SHOT RETURN "Elk (Rear)"
|
|
CASE KILL_LEG_SHOT RETURN "Elk (Leg)"
|
|
CASE KILL_SPOOKED_SHOT RETURN "Elk (Spooked)"
|
|
CASE KILL_DOE_KILL RETURN "Doe"
|
|
CASE KILL_MOUNTAIN_LION_KILL RETURN "Mountain Lion"
|
|
CASE KILL_BOAR_KILL RETURN "Boar"
|
|
CASE KILL_COYOTE_KILL RETURN "Coyote"
|
|
CASE KILL_BIRD_KILL RETURN "Bird"
|
|
CASE KILL_HUMAN_KILL RETURN "Human"
|
|
CASE KILL_ROAD_KILL
|
|
SWITCH GET_ENTITY_MODEL(entCorpse)
|
|
CASE A_C_DEER
|
|
IF IS_ELK_A_DOE(entCorpse)
|
|
RETURN "Doe (Roadkill)"
|
|
ELSE
|
|
RETURN "Elk (Roadkill)"
|
|
ENDIF
|
|
BREAK
|
|
CASE A_C_MTLION RETURN "Mountain Lion (Roadkill)"
|
|
CASE A_C_BOAR RETURN "Boar (Roadkill)"
|
|
CASE A_C_COYOTE RETURN "Coyote (Roadkill)"
|
|
DEFAULT RETURN "Unknown Roadkill"
|
|
ENDSWITCH
|
|
BREAK
|
|
CASE KILL_LIVE_ANIMAL
|
|
SWITCH GET_ENTITY_MODEL(entCorpse)
|
|
CASE A_C_DEER
|
|
IF IS_ELK_A_DOE(entCorpse)
|
|
RETURN "Doe (Live)"
|
|
ELSE
|
|
RETURN "Elk (Live)"
|
|
ENDIF
|
|
BREAK
|
|
CASE A_C_MTLION RETURN "Mountain Lion (Live)"
|
|
CASE A_C_BOAR RETURN "Boar (Live)"
|
|
CASE A_C_COYOTE RETURN "Coyote (Live)"
|
|
DEFAULT RETURN "Unknown Live Animal"
|
|
ENDSWITCH
|
|
BREAK
|
|
ENDSWITCH
|
|
RETURN "Unknown Photo Subject"
|
|
ENDFUNC
|
|
|
|
#ENDIF
|
|
/// PURPOSE:
|
|
/// Stop the sniper audio from activating. Used to stop the audio playing on the results screen
|
|
/// and if we need to free up audio slots to play the mission passed theme.
|
|
PROC STOP_SNIPE_AUDIO()
|
|
IF IS_AUDIO_SCENE_ACTIVE("HUNTING_02_SETTINGS")
|
|
STOP_AUDIO_SCENE("HUNTING_02_SETTINGS")
|
|
STOP_SOUND(iSoundID)
|
|
RELEASE_SOUND_ID(iSoundID)
|
|
iSoundID = -1
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Triggers an ambient speech line from the player if he hasn't commented recently.
|
|
PROC TRIGGER_HUNTING_AUDIO(STRING sAmbientSpeech, BOOL bAllowOverlap = FALSE)
|
|
// Don't trigger too recently, unless we're allowed to overlap.
|
|
IF NOT bAllowOverlap
|
|
AND Player_Hunt_Data.iLastCommentTime > GET_GAME_TIMER()
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Trigger the dialogue & delay the next one.
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE_NATIVE(PLAYER_PED_ID(), sAmbientSpeech, "TREVOR_NORMAL", AUDIO_SPEECH_GET_PARAM_STRING_FROM_ENUM(SPEECH_PARAMS_FORCE))
|
|
Player_Hunt_Data.iLastCommentTime += HUNTING_COMMENT_DELAY
|
|
ENDPROC
|
|
|
|
|
|
// Try to supress the global help text displaying when the select screen is on screen.
|
|
PROC SUPRESS_HELP_TEXT()
|
|
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_ARMST")
|
|
OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FTXT")
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
PROC CHALLENGE_NOTIFICATION( STRING sText, INT iScore, INT iScoreGoal )
|
|
BEGIN_TEXT_COMMAND_THEFEED_POST( sText )
|
|
|
|
ADD_TEXT_COMPONENT_INTEGER(iScore)
|
|
ADD_TEXT_COMPONENT_INTEGER(iScoreGoal)
|
|
END_TEXT_COMMAND_THEFEED_POST_TICKER(FALSE)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Sets whether or not elk will randomly make noise and call.
|
|
/// Does not stop the reply to the elk call.
|
|
PROC SET_ELK_RANDOM_CALLS_ENABLED(MY_ELK & thisElk, BOOL bRandomCallsEnabled)
|
|
thisElk.bRandomlyCalls = bRandomCallsEnabled
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Sets whether an elk will have a 75% chance of replying to a call, or a 100% chance.
|
|
PROC SET_ELK_MUST_REPLY_TO_CALL(MY_ELK & thisElk, BOOL bMustReplyToCall)
|
|
thisElk.bMustReplyToCall = bMustReplyToCall
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Stores in globals that the player has hunted, and a week from now, he'll be getting old conversations.
|
|
/// This is so that if the player makes phonecalls in ambient hunting, he's given a proper conversation.
|
|
PROC SET_TIME_LAST_HUNTED(BOOL bAwesomeHunt = FALSE)
|
|
g_SavedGlobals.sAmbient.todHuntedWeekExp = GET_CURRENT_TIMEOFDAY()
|
|
ADD_TIME_TO_TIMEOFDAY(g_SavedGlobals.sAmbient.todHuntedWeekExp, 0, 0, 0, 7)
|
|
|
|
// Player's hunted recently.
|
|
CANCEL_COMMUNICATION(CHAT_CLE1_1)
|
|
CANCEL_COMMUNICATION(CHAT_CLE1_2)
|
|
CANCEL_COMMUNICATION(CHAT_CLE2_1)
|
|
CANCEL_COMMUNICATION(CHAT_CLE2_2)
|
|
CANCEL_COMMUNICATION(CHAT_CLE3_1)
|
|
|
|
// Re-add the proper conversations. If it was an awesome hunt, we trigger that. Otherwise
|
|
IF bAwesomeHunt
|
|
PRINTLN("--------------------------------- PLAYER HAD GREAT HUNT! ADDING CONVO 3! ---------------------------------")
|
|
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE3_1, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
|
|
ELSE
|
|
PRINTLN("--------------------------------- PLAYER HAD OKAY HUNT, ADDING CONVO 1 & 2! ---------------------------------")
|
|
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE1_1, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
|
|
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE1_2, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Adds blip to Peds first checking that the blip doesnt exist then if the ped is ok. Also can set the ped to be enemy blip or not
|
|
PROC ADD_SAFE_BLIP_TO_PED(BLIP_INDEX &blipIn, PED_INDEX pedIndex, BOOL bEnemy = TRUE, FLOAT fScale = 1.0)
|
|
IF NOT DOES_BLIP_EXIST(blipIn)
|
|
IF IS_PED_UNINJURED(pedIndex)
|
|
blipIn = CREATE_BLIP_FOR_PED(pedIndex, bEnemy)
|
|
SET_BLIP_SCALE(blipIn, fScale)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Loads the elk model.
|
|
PROC LOAD_ELK_MODEL()
|
|
REQUEST_MODEL(A_C_DEER)
|
|
WHILE NOT HAS_MODEL_LOADED(A_C_DEER)
|
|
WAIT(0)
|
|
ENDWHILE
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Requests a model and checks that it has loaded
|
|
/// PARAMS:
|
|
/// _modname - The name of the model to load
|
|
/// _debugstring - The string to print -purely debug
|
|
/// i - an index to be printed in case you are loading models that are referenced in an array
|
|
/// RETURNS:
|
|
/// TRUE if the model loaded
|
|
FUNC BOOL REQUEST_AND_CHECK_MODEL(MODEL_NAMES _modname)
|
|
REQUEST_MODEL(_modname)
|
|
|
|
IF HAS_MODEL_LOADED(_modname)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// To confuse the living piss out of anyone who tries to use it, read it
|
|
/// or, god forbid, try to debug it. I don't even...
|
|
/// Spawns a ped and returns true if it was succesful
|
|
/// Loads the model and unloads the model if the ped was created properly
|
|
/// PARAMS:
|
|
/// pedindex - The ped index to write the newly created ped to
|
|
/// model - The model the ped should be created with
|
|
/// pos - The postion the ped should be created at
|
|
/// dir - The heading the ped should have
|
|
/// RETURNS:
|
|
/// TRUE if the ped was created sucessfully
|
|
FUNC BOOL SPAWN_PED(PED_INDEX &pedindex, MODEL_NAMES model, VECTOR pos, FLOAT dir, BOOL bUnload = TRUE, BOOL bIsHunter = FALSE, BOOL bForceElkDoe = FALSE)
|
|
IF NOT DOES_ENTITY_EXIST(pedindex)
|
|
IF REQUEST_AND_CHECK_MODEL(model)
|
|
|
|
pedindex = CREATE_PED(PEDTYPE_MISSION, model, pos, dir)
|
|
|
|
IF NOT bIsHunter
|
|
// Deer are a special case. They need to be tagged, have antlers, and can only have so many doe in play at once.
|
|
IF (model = A_C_DEER)
|
|
BOOL bSpawnElk = TRUE
|
|
|
|
// See if we should & can spawn a doe.
|
|
IF (iDoeInPlay < MAX_DOE_IN_PLAY) OR bForceElkDoe
|
|
FLOAT fPctDoes = 50.0
|
|
IF (iElksInPlay != 0)
|
|
// Careful not to divide by 0...
|
|
fPctDoes = TO_FLOAT(iDoeInPlay) / TO_FLOAT(iElksInPlay)
|
|
|
|
// We don't get a proper percent because we actually want to skew towards spawning doe.
|
|
// This is because doe will inevitably fill up anyway, and we'll be forced to make elk.
|
|
fPctDoes *= 75.0
|
|
ENDIF
|
|
|
|
IF GET_RANDOM_INT_IN_RANGE(0, 100) > fPctDoes
|
|
OR bForceElkDoe
|
|
SET_PED_COMPONENT_VARIATION(pedindex, PED_COMP_SPECIAL, 0, 0)
|
|
DECOR_SET_BOOL(pedindex, "doe_elk", TRUE)
|
|
bSpawnElk = FALSE
|
|
|
|
iDoeInPlay += 1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// If we still need to spawn, that means eithe rwe shouldn't have, or couldn't have spawned a doe.
|
|
IF bSpawnElk
|
|
SET_PED_COMPONENT_VARIATION(pedindex, PED_COMP_SPECIAL, 1, 0) // GIVE HIM ANTLERS
|
|
IF DECOR_EXIST_ON(pedindex, "doe_elk")
|
|
DECOR_REMOVE(pedindex, "doe_elk")
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Deer have 3 color variants.
|
|
SET_PED_COMPONENT_VARIATION(pedindex, PED_COMP_HEAD, 0, GET_RANDOM_INT_IN_RANGE(0, 3)) // Change fur color
|
|
ELIF (model = A_C_MTLION)
|
|
// Mountain lions have 3 color variants.
|
|
SET_PED_COMPONENT_VARIATION(pedindex, PED_COMP_HEAD, 0, GET_RANDOM_INT_IN_RANGE(0, 3)) // Change fur color
|
|
ELIF (model = A_C_BOAR)
|
|
// Boar have 4 color variants.
|
|
SET_PED_COMPONENT_VARIATION(pedindex, PED_COMP_HEAD, 0, GET_RANDOM_INT_IN_RANGE(0, 4)) // Change fur color
|
|
ENDIF
|
|
|
|
// Make the boar visible from far away.
|
|
SET_ENTITY_LOD_DIST(pedindex, 1500)
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(pedindex, TRUE)
|
|
SET_PED_LOD_MULTIPLIER(pedindex, 5.0)
|
|
ENDIF
|
|
|
|
IF bUnload
|
|
SET_MODEL_AS_NO_LONGER_NEEDED(model)
|
|
ENDIF
|
|
|
|
IF DOES_ENTITY_EXIST(pedindex)
|
|
SET_PED_CAN_BE_TARGETTED(pedindex, FALSE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
RETURN FALSE
|
|
ENDIF
|
|
ELSE
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Spawns and sets up a ped with a debug name
|
|
/// Basic function that can be expanded on
|
|
/// PARAMS:
|
|
/// index - The ped index to write the new ped to
|
|
/// pos - The position to create ped
|
|
/// fDir - The heading to give ped
|
|
/// modelName - The model to create the ped with
|
|
/// RETURNS:
|
|
/// TRUE if the ped was created properly
|
|
FUNC BOOL SETUP_PED(PED_INDEX &index, VECTOR pos, FLOAT fDir, MODEL_NAMES modelName, BOOL bUnload = TRUE, BOOL bForceElkDoe = FALSE)
|
|
IF SPAWN_PED(index, modelName, pos, fDir, bUnload, DEFAULT, bForceElkDoe)
|
|
IF IS_PED_UNINJURED(index)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
// Gradually reduces the vehicle density in the world.
|
|
PROC DIAL_DOWN_TRAFFIC()
|
|
IF fCarDensity > 0.0
|
|
IF NOT bGotDialDownTime
|
|
iDialDownTime = GET_GAME_TIMER() + 3000
|
|
bGotDialDownTime = TRUE
|
|
ELSE
|
|
IF GET_GAME_TIMER() > iDialDownTime
|
|
fCarDensity = fCarDensity - 0.1
|
|
//CPRINTLN(DEBUG_MISSION,"DIALING DOWN TRAFFIC TO ", fCarDensity)
|
|
bGotDialDownTime = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//CPRINTLN(DEBUG_MISSION,"DIALING DOWN TRAFFIC TO ", fCarDensity)
|
|
SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(fCarDensity)
|
|
ENDPROC
|
|
|
|
/// GIVES THE PLAYER A SNIPER RIFLE, IF HE DOESN'T ALREADY HAVE ONE
|
|
PROC SAFE_GIVE_SNIPER_TO_PLAYER(BOOL bForceToHand = TRUE)
|
|
PED_INDEX pedPlayer = PLAYER_PED_ID()
|
|
IF IS_PED_UNINJURED(pedPlayer)
|
|
IF NOT HAS_PED_GOT_WEAPON(pedPlayer, WEAPONTYPE_SNIPERRIFLE, GENERALWEAPON_TYPE_INVALID)
|
|
// Need to give the sniper rifle!
|
|
CDEBUG2LN( DEBUG_MISSION, "SAFE_GIVE_SNIPER_TO_PLAYER player didn't have sniper rifle" )
|
|
bHadSniperRifle = FALSE
|
|
GIVE_WEAPON_TO_PED(pedPlayer, WEAPONTYPE_SNIPERRIFLE, INFINITE_AMMO, bForceToHand, TRUE)
|
|
ELSE
|
|
// Player had sniper rifle. Just set infinite ammo and suppressor.
|
|
bHadSniperRifle = TRUE
|
|
SET_CURRENT_PED_WEAPON(pedPlayer, WEAPONTYPE_SNIPERRIFLE, bForceToHand)
|
|
iSniperAmmoBefore = GET_PED_AMMO_BY_TYPE(pedPlayer, AMMOTYPE_SNIPER)
|
|
IF iSniperAmmoBefore = 0
|
|
CDEBUG2LN( DEBUG_MISSION, "SAFE_GIVE_SNIPER_TO_PLAYER ammo was 0, setting with SET_PED_AMMO_BY_TYPE and SET_AMMO_IN_CLIP." )
|
|
SET_PED_AMMO_BY_TYPE( pedPlayer, AMMOTYPE_SNIPER, 20 )
|
|
SET_AMMO_IN_CLIP( pedPlayer, WEAPONTYPE_SNIPERRIFLE, 10 )
|
|
WAIT(0)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF NOT HAS_PED_GOT_WEAPON_COMPONENT(pedPlayer, WEAPONTYPE_SNIPERRIFLE, WEAPONCOMPONENT_AT_AR_SUPP_02)
|
|
bHadSuppressor = FALSE
|
|
GIVE_WEAPON_COMPONENT_TO_PED(pedPlayer, WEAPONTYPE_SNIPERRIFLE, WEAPONCOMPONENT_AT_AR_SUPP_02)
|
|
ELSE
|
|
bHadSuppressor = TRUE
|
|
ENDIF
|
|
|
|
SET_PED_INFINITE_AMMO(pedPlayer, TRUE, WEAPONTYPE_SNIPERRIFLE)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC RETURN_PLAYERS_GUN(BOOL bForceCleanup = FALSE)
|
|
PED_INDEX pedPlayer = PLAYER_PED_ID()
|
|
IF IS_PED_UNINJURED(pedPlayer) OR bForceCleanup
|
|
// Regardless, don't set the player to infinite ammo.
|
|
SET_PED_INFINITE_AMMO(pedPlayer, FALSE, WEAPONTYPE_SNIPERRIFLE)
|
|
SET_PED_AMMO_BY_TYPE(pedPlayer, AMMOTYPE_SNIPER, iSniperAmmoBefore)
|
|
|
|
IF NOT bHadSuppressor
|
|
IF HAS_PED_GOT_WEAPON_COMPONENT(pedPlayer, WEAPONTYPE_SNIPERRIFLE, WEAPONCOMPONENT_AT_AR_SUPP_02)
|
|
REMOVE_WEAPON_COMPONENT_FROM_PED(pedPlayer, WEAPONTYPE_SNIPERRIFLE, WEAPONCOMPONENT_AT_AR_SUPP_02)
|
|
ENDIF
|
|
ENDIF
|
|
IF NOT bHadSniperRifle
|
|
REMOVE_WEAPON_FROM_PED(pedPlayer, WEAPONTYPE_SNIPERRIFLE)
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
FUNC BOOL CAN_PLAYER_SEE_POINT(VECTOR vPos, FLOAT fRadius = 5.0, INT distance = 120)
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
FLOAT fDiff = GET_DISTANCE_BETWEEN_COORDS( GET_ENTITY_COORDS(PLAYER_PED_ID()), vPos)
|
|
IF fDiff <= distance
|
|
IF IS_SPHERE_VISIBLE(vPos, fRadius)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL DOES_PLAYER_HAVE_RIFLE_EQUIPT()
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
IF GET_WEAPONTYPE_GROUP(GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID())) = WEAPONGROUP_SNIPER
|
|
//CPRINTLN(DEBUG_MISSION, "PLAYER HAS SNIPER")
|
|
IF NOT bSniperEquiped
|
|
bSniperEquiped = TRUE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL IS_PLAYER_IN_IMMEDIATE_HUNT_AREA()
|
|
VECTOR vPos
|
|
vPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
|
|
IF IS_POINT_IN_POLY_2D(mAreaCheck1, vPos)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL IS_PLAYER_IN_OUTER_HUNT_AREA()
|
|
VECTOR vPos
|
|
vPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
|
|
IF IS_POINT_IN_POLY_2D(mAreaCheck2, vPos)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Turn off the ambient services
|
|
PROC SERVICES_TOGGLE(BOOL bOn)
|
|
//Wanted
|
|
ENABLE_DISPATCH_SERVICE(DT_POLICE_AUTOMOBILE, bOn)
|
|
ENABLE_DISPATCH_SERVICE(DT_POLICE_HELICOPTER, bOn)
|
|
ENABLE_DISPATCH_SERVICE(DT_FIRE_DEPARTMENT, bOn)
|
|
ENABLE_DISPATCH_SERVICE(DT_SWAT_AUTOMOBILE, bOn)
|
|
ENABLE_DISPATCH_SERVICE(DT_AMBULANCE_DEPARTMENT, bOn)
|
|
|
|
IF bOn
|
|
//SET_VEHICLE_DENSITY_MULTIPLIER(1.0)
|
|
SET_WANTED_LEVEL_MULTIPLIER(1.0)
|
|
SET_MAX_WANTED_LEVEL(5)
|
|
ELSE
|
|
SET_MAX_WANTED_LEVEL(0)
|
|
SET_WANTED_LEVEL_MULTIPLIER(0.0)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
// ==================
|
|
// ELK FUNCTIONS
|
|
// ==================
|
|
|
|
// Used in hunt2
|
|
FUNC INT GET_SPOOKED_REASON(INT i)
|
|
RETURN ENUM_TO_INT(mElk[i].eSpookedReason)
|
|
ENDFUNC
|
|
|
|
// RETURNS TRUE IF THE ELK EXISTS AND IS NOT DEAD
|
|
FUNC BOOL IS_ELK_OK(INT i)
|
|
RETURN DOES_ENTITY_EXIST(mElk[i].mPed) AND NOT IS_ENTITY_DEAD(mElk[i].mPed)
|
|
ENDFUNC
|
|
|
|
FUNC BOOL IS_ANY_ELK_OK()
|
|
INT i = 0
|
|
REPEAT MAX_ELKS i
|
|
IF IS_ELK_OK (i)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDREPEAT
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if any of the main pool of elks is currently a herd member (Only one herd can be active at a time)
|
|
/// RETURNS:
|
|
///
|
|
FUNC BOOL IS_ANY_ELK_A_HERD_MEMBER()
|
|
INT i = 0
|
|
WHILE i < MAX_ELKS
|
|
|
|
IF IS_ELK_OK(i)
|
|
IF mElk[i].bIsHerdMember
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
++ i
|
|
ENDWHILE
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
// RETURNS TRUE IF ANY ELK HAS BEEN DAMAGED BY THE PLAYER
|
|
FUNC BOOL HAS_PLAYER_SHOT_ELK(INT i)
|
|
IF IS_ELK_OK(i)
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(mElk[i].mPed, PLAYER_PED_ID())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Spooks or unspooks the Elk in mElk[i]
|
|
/// PARAMS:
|
|
/// i - The index of the elk to spook
|
|
PROC SET_ELK_SPOOKED( INT i, BOOL bSpook )
|
|
|
|
IF i < 0 OR i >= MAX_ELKS
|
|
DEBUG_PRINTCALLSTACK()
|
|
CWARNINGLN( DEBUG_MISSION, "SET_ELK_SPOOKED exiting, i is out of bounds, i=", i )
|
|
EXIT
|
|
ENDIF
|
|
|
|
CDEBUG2LN( DEBUG_MISSION, "SET_ELK_SPOOKED setting elk i=", i, " to ", PICK_STRING( bSpook, "TRUE", "FALSE" ) )
|
|
|
|
mElk[i].bIsSpooked = bSpook
|
|
|
|
ENDPROC
|
|
|
|
// Used in non-ambient missions to get the Elk to flee and set the appropriate fail message.
|
|
PROC FORCE_ELK_FLEE(INT i)
|
|
IF NOT bIsAmbient
|
|
IF IS_ENTITY_ALIVE(mElk[i].mPed)
|
|
CPRINTLN(DEBUG_MISSION,"FORCE ELK FLEE ", i)
|
|
SET_ENTITY_PROOFS(mElk[i].mPed, TRUE, FALSE, FALSE, FALSE, FALSE)
|
|
TASK_SMART_FLEE_PED(mElk[i].mPed, PLAYER_PED_ID(), 500.0, -1, FALSE)
|
|
SET_PED_KEEP_TASK(mElk[i].mPed, TRUE)
|
|
ENDIF
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_ELK_CLOSE_TO_SPOOKED_ELK(INT i)
|
|
|
|
INT j = 0
|
|
REPEAT MAX_ELKS j
|
|
IF j <> i
|
|
IF IS_ELK_OK(j)
|
|
IF mElk[j].bIsSpooked
|
|
IF (GET_DISTANCE_BETWEEN_ENTITIES (mElk[i].mPed, mElk[j].mPed)) < 10.0
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
// SHOULD WE TURN THE WIND DIRECTION ARROW RED
|
|
FUNC BOOL PLAYER_CLOSE_TO_BEING_DETECTED()
|
|
|
|
INT i = 0
|
|
REPEAT MAX_ELKS i
|
|
IF IS_ELK_OK(i) AND NOT mElk[i].bIsSpooked
|
|
|
|
VECTOR vNormal = NORMALISE_VECTOR(mElk[i].vScentOffsetPos+<<0,0,ELK_SCENT_RANGE>> - mElk[i].vPos+<<0,0,-ELK_SCENT_RANGE>>)
|
|
VECTOR vA = (mElk[i].vPos + <<0.0, 0.0, ELK_SCENT_RANGE>>)// - (vNormal * 45.0)
|
|
VECTOR vB = (mElk[i].vScentOffsetPos + <<0.0, 0, -ELK_SCENT_RANGE >>) + (vNormal * 45.0)
|
|
|
|
// DRAW_DEBUG_AREA(mElk[i].vPos + <<0.0, 0.0, ELK_SCENT_RANGE>>, mElk[i].vScentOffsetPos + <<0.0, 0, -ELK_SCENT_RANGE >>, ELK_SCENT_WIDTH, 255, 255, 255)
|
|
// DRAW_DEBUG_AREA(vA, vB, ELK_SCENT_WIDTH+15, 74, 44, 14)
|
|
|
|
IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), vA, vB, ELK_SCENT_WIDTH+20, FALSE, FALSE, TM_ANY)
|
|
IF bIsAmbient
|
|
IF NOT Player_Hunt_Data.bSentDownwindHelp
|
|
IF NOT IS_MESSAGE_BEING_DISPLAYED()
|
|
PRINT_HELP("AHT_DOWNWIND")
|
|
Player_Hunt_Data.bSentDownwindHelp = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDREPEAT
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Forces all elk associated with a particular herd to scatter and flee.
|
|
/// PARAMS:
|
|
/// idxMemberOrLeader - index of either a member elk or leader elk.
|
|
PROC FORCE_ELK_HERD_SCATTER(INT idxMemberOrLeader)
|
|
INT iLeaderIdx = idxMemberOrLeader
|
|
IF mElk[idxMemberOrLeader].bIsHerdMember
|
|
// Okay, get it's leader.
|
|
iLeaderIdx = mElk[idxMemberOrLeader].iLeaderIdx
|
|
ENDIF
|
|
|
|
SET_ELK_SPOOKED(idxMemberOrLeader, TRUE)
|
|
mElk[idxMemberOrLeader].bIsHerdLeader = FALSE
|
|
mElk[idxMemberOrLeader].bIsHerdMember = FALSE
|
|
mElk[idxMemberOrLeader].iLeaderIdx = -1
|
|
|
|
// Otherwise, this was already the leader.
|
|
// Loop through all elk. Any living elk that claims this index as it's leader's index needs to spook.
|
|
INT idx
|
|
REPEAT MAX_ELKS idx
|
|
// Leader check is cheap, do that first.
|
|
IF (mElk[idx].iLeaderIdx = iLeaderIdx)
|
|
IF DOES_ENTITY_EXIST(mElk[idx].mPed)
|
|
AND NOT IS_ENTITY_DEAD(mElk[idx].mPed)
|
|
FORCE_ELK_FLEE(idx)
|
|
|
|
// Need to set our fleeing reason.
|
|
mElk[idx].eSpookedReason = SR_SPOOKED_BY_ELK
|
|
|
|
// Lastly, this elk needs to leave the herd.
|
|
SET_ELK_SPOOKED(idx, TRUE)
|
|
mElk[idx].bIsHerdLeader = FALSE
|
|
mElk[idx].bIsHerdMember = FALSE
|
|
mElk[idx].iLeaderIdx = -1
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE: Checks whether the Elk has detected the player
|
|
/// RETURNS: TRUE if the player is in the elk's line of sight,
|
|
/// or if you are downwind of the elk,
|
|
/// or within 15 metres of it in any direction making noise.
|
|
PROC CHECK_ELK_SPOOKED(INT i)
|
|
BOOL bWasAlreadySpooked = mElk[i].bIsSpooked
|
|
IF IS_ELK_OK(i) AND NOT mElk[i].bIsSpooked
|
|
mElk[i].vPos = GET_ENTITY_COORDS(mElk[i].mPed, FALSE)
|
|
mElk[i].fDist = GET_DISTANCE_BETWEEN_COORDS(mElk[i].vPos, GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), FALSE)
|
|
mElk[i].vScentOffsetPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(mElk[i].vPos, fWindDirection, -SCENT_RANGE)
|
|
|
|
IF CAN_PED_SEE_HATED_PED(mElk[i].mPed, PLAYER_PED_ID())
|
|
IF bIsAmbient
|
|
PRINT_HELP("AHT_CROUCH") // THE ELK SAW YOU. STAY OUT OF ITS LINE OF SIGHT
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION,"CHECKING FROM HUNTIN2 - ELK SAW YOU")
|
|
PRINT_HELP ("HT_CROUCH") // THE ELK SAW YOU. STAY OUT OF ITS LINE OF SIGHT
|
|
FORCE_ELK_FLEE(i)
|
|
mElk[i].eSpookedReason = SR_SAW_PLAYER // So we can pass the spooked reason over to the hunting 2 script
|
|
ENDIF
|
|
|
|
//CPRINTLN(DEBUG_MISSION, "Setting spooked flag - spotted player")
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ENDIF
|
|
|
|
// Is the player just so close that the elk would have to know he's there?
|
|
IF (mElk[i].fDist < k_ELK_SPOOK_RANGE)
|
|
IF bIsAmbient
|
|
PRINT_HELP("AHT_NOTICED") // If elk detect danger close nearby, they will flee.
|
|
ELSE
|
|
PRINT_HELP("HT_HEARD")
|
|
ENDIF
|
|
mElk[i].eSpookedReason = SR_HEARD_PLAYER
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ENDIF
|
|
|
|
// CAN THE ELK SMELL THE PLAYER
|
|
IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), mElk[i].vPos+<<0,0,-ELK_SCENT_RANGE>>, mElk[i].vScentOffsetPos+<<0,0,ELK_SCENT_RANGE>>, ELK_SCENT_WIDTH, FALSE, FALSE, TM_ANY)
|
|
IF bIsAmbient
|
|
PRINT_HELP("AHT_SCENT") // THE ELK PICKED UP YOUR SCENT. ALWAYS TRY TO STAY DOWNWIND FROM YOUR QUARRY
|
|
ELSE
|
|
PRINT_HELP ("HT_SCENT") // THE ELK PICKED UP YOUR SCENT. ALWAYS TRY TO STAY DOWNWIND FROM YOUR QUARRY
|
|
ENDIF
|
|
|
|
FORCE_ELK_FLEE(i)
|
|
mElk[i].eSpookedReason = SR_SMELLED_PLAYER
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ENDIF
|
|
|
|
// CAN THE ELK HEAR THE PLAYER?
|
|
IF CAN_PED_HEAR_PLAYER(PLAYER_ID(), mElk[i].mPed)
|
|
IF bIsAmbient
|
|
PRINT_HELP("AHT_HEARD") // THE ELK HEARD YOU. WHEN CLOSE, USE STEALTH TO HELP REMAIN UNDETECTED
|
|
ELSE
|
|
FORCE_ELK_FLEE(i)
|
|
PRINT_HELP("HT_HEARD") // THE ELK HEARD YOU. WHEN CLOSE, USE STEALTH TO HELP REMAIN UNDETECTED
|
|
mElk[i].eSpookedReason = SR_HEARD_PLAYER
|
|
ENDIF
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ENDIF
|
|
|
|
// HAS THE ELK COME CLOSE TO ANOTHER SPOOKED ELK?
|
|
IF IS_ELK_CLOSE_TO_SPOOKED_ELK(i)
|
|
IF NOT bIsAmbient
|
|
FORCE_ELK_FLEE(i)
|
|
mElk[i].eSpookedReason = SR_SPOOKED_BY_ELK
|
|
ENDIF
|
|
|
|
CPRINTLN(DEBUG_MISSION,"Setting spooked flag - spooked by a fleeing elk")
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ENDIF
|
|
|
|
// HAS THE ELK BEEN SPOOKED BY A NEAR MISS?
|
|
IF IS_ANYONE_SHOOTING_NEAR_PED(mElk[i].mPed)
|
|
IF NOT bGotNearMissTime
|
|
CPRINTLN(DEBUG_MISSION, "bullet too close to elk ", i )
|
|
iMissMessageDelay = GET_GAME_TIMER() + MISS_MESSAGE_DELAY_TIME
|
|
bGotNearMissTime = TRUE
|
|
ENDIF
|
|
|
|
IF bIsAmbient
|
|
TRIGGER_HUNTING_AUDIO("HUNTING_MISSED")
|
|
iLocalKillCount = Player_Hunt_Data.iScore
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
ELSE
|
|
FORCE_ELK_FLEE(i)
|
|
SET_ELK_SPOOKED(i, TRUE)
|
|
mElk[i].eSpookedReason = SR_NEAR_MISS
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF bGotNearMissTime
|
|
//CPRINTLN(DEBUG_MISSION, "This elk has a near miss time ", i )
|
|
|
|
// Only show the "You missed" message if, after a second, the kill count hasn't gone up
|
|
// or the message isn't being suppressed by a recent kill
|
|
IF GET_GAME_TIMER() > iMissMessageDelay
|
|
IF iLocalKillCount = Player_Hunt_Data.iScore AND NOT bSuppressNearMissMessage
|
|
IF bIsAmbient
|
|
// Don't really want to notify the player that he missed an elk if he didn't even see the elk he missed.
|
|
//IF WOULD_ENTITY_BE_OCCLUDED(A_C_DEER, mElk[i].vPos, FALSE)
|
|
PRINT_HELP("AHT_MISS") // YOU MISSED AND SPOOKED THE ELK. BE SURE TO HIT THE TARGET NEXT TIME
|
|
//ENDIF
|
|
ELSE
|
|
PRINT_HELP("HT_MISS") // YOU MISSED AND SPOOKED THE ELK. BE SURE TO HIT THE TARGET NEXT TIME
|
|
ENDIF
|
|
ENDIF
|
|
|
|
bShouldClearSuppressNearMissMsg = TRUE
|
|
bGotNearMissTime = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
IF mElk[i].bIsSpooked AND NOT bWasAlreadySpooked
|
|
// Reset the kills since spooked counter
|
|
Player_Hunt_Data.iKillsSinceSpooked = 0
|
|
|
|
// If he's a herd member, he scatters.
|
|
IF mElk[i].bIsHerdMember OR mElk[i].bIsHerdLeader
|
|
FORCE_ELK_HERD_SCATTER(i)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
// RETURNS TRUE IF THE PLAYER CAN SEE ANY ELK
|
|
FUNC BOOL CAN_PLAYER_SEE_ELK(INT i)
|
|
|
|
IF IS_ELK_OK(i)
|
|
IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), mElk[i].mPed, 150.0) AND IS_ENTITY_ON_SCREEN(mElk[i].mPed)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks to see if the player has pressed the call button
|
|
/// PARAMS:
|
|
/// i - the index of the elk to use when checking
|
|
INT iResponseTime
|
|
INT iCallEndTime
|
|
INT iWhistleDelay = -1
|
|
INT iWhistleCallTime
|
|
//BOOL bShowNoiseBlip
|
|
|
|
CONST_INT CALL_DURATION 4000
|
|
CONST_INT FADE_DELAY_TIME 4000
|
|
CONST_INT RESPONSE_DELAY 3500
|
|
CONST_INT WHISTLE_CALL_TIME 2500
|
|
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Returns the MS to wait for a shapetest given the distance something is from the player.
|
|
FUNC INT GET_HARD_BLIP_DELAY_TIME(FLOAT fDist)
|
|
IF (fDist > 180)
|
|
RETURN 3500
|
|
ELIF (fDist > 120)
|
|
RETURN 2500
|
|
ELIF (fDist > 50)
|
|
RETURN 2000
|
|
ENDIF
|
|
|
|
// Always wait at least a second.
|
|
RETURN 1000
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Runs a shapetest on an occluded ped.
|
|
/// RETURNS:
|
|
/// 1 if the test passed. 0 to keep processing. -1 if it failed and is done.
|
|
FUNC INT RUN_SHAPE_TEST_FOR_ELK(MY_ELK & thisElk, VECTOR vElkCoord, FLOAT fDistToPlayer)
|
|
IF (elkShapeTest = NULL)
|
|
//PRINTLN("Starting shapetest on elk: ", iAnimalIdx)
|
|
VECTOR vStart = vHuntingPlayerCoords + <<0,0,0.75>>
|
|
elkShapeTest = START_SHAPE_TEST_LOS_PROBE(vStart, vElkCoord)
|
|
ELSE
|
|
INT iHit
|
|
VECTOR vHitPos, vNormal
|
|
ENTITY_INDEX entHit
|
|
//PRINTLN("Processing shapetest on animal: ", iAnimalIdx)
|
|
SHAPETEST_STATUS eResult = GET_SHAPE_TEST_RESULT(elkShapeTest, iHit, vHitPos, vNormal, entHit)
|
|
IF (eResult = SHAPETEST_STATUS_RESULTS_READY)
|
|
//PRINTLN("Shapetest results -- iHit: ", iHit, ", vPos: ", vHitPos, ", entHit: ", NATIVE_TO_INT(entHit))
|
|
IF (iHit = 0)
|
|
// PASSED!
|
|
//PRINTLN("Elk passed shapetest: ", vElkCoord)
|
|
thisElk.iNextTestTime = GET_GAME_TIMER() + GET_HARD_BLIP_DELAY_TIME(fDistToPlayer)
|
|
iElkTesting = -1
|
|
elkShapeTest = NULL
|
|
|
|
RETURN 1
|
|
ELSE
|
|
// FAILED
|
|
//PRINTLN("Elk failed shapetest: ", vElkCoord)
|
|
thisElk.iNextTestTime = GET_GAME_TIMER() + GET_HARD_BLIP_DELAY_TIME(fDistToPlayer)
|
|
iElkTesting = -1
|
|
elkShapeTest = NULL
|
|
|
|
RETURN -1
|
|
ENDIF
|
|
ELIF (eResult = SHAPETEST_STATUS_NONEXISTENT)
|
|
//PRINTLN("No test result. Going to null: ", iAnimalIdx)
|
|
//PRINTLN("No shapetest: ", vElkCoord)
|
|
iElkTesting = -1
|
|
elkShapeTest = NULL
|
|
|
|
RETURN -1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//PRINTLN("Processing shapetest: ", vElkCoord)
|
|
RETURN 0
|
|
ENDFUNC
|
|
|
|
|
|
PROC MANAGE_ELK_BLIP(MY_ELK &thisElk, INT iElkIndex)
|
|
IF NOT IS_ELK_OK(iElkIndex)
|
|
IF DOES_BLIP_EXIST(thisElk.mElkBlip)
|
|
CPRINTLN(DEBUG_MISSION, "Remove existing blip on Elk that's not okay.")
|
|
REMOVE_BLIP(thisElk.mElkBlip)
|
|
ENDIF
|
|
EXIT
|
|
ENDIF
|
|
IF thisElk.bIsSpooked
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Distance is needed no matter what.
|
|
VECTOR vDeerCoord = GET_ENTITY_COORDS(thisElk.mPed)
|
|
FLOAT distToPlayer = GET_DISTANCE_BETWEEN_COORDS(vHuntingPlayerCoords, vDeerCoord)
|
|
BOOL bOnScreen = IS_ENTITY_ON_SCREEN(thisElk.mPed)
|
|
|
|
// Hard blipping will be checked first.
|
|
IF NOT thisElk.bHardBlipped
|
|
BOOL bOccluded = TRUE
|
|
IF bOnScreen AND (thisElk.iNextTestTime < GET_GAME_TIMER())
|
|
AND (distToPlayer < fDistanceThreshold)
|
|
AND (iElkTesting = iElkIndex OR iElkTesting = -1)
|
|
// Flag us as the tester!
|
|
iElkTesting = iElkIndex
|
|
|
|
INT iResult = RUN_SHAPE_TEST_FOR_ELK(thisElk, vDeerCoord, distToPlayer)
|
|
IF (iResult = 1)
|
|
// Passed!
|
|
bOccluded = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Blip the deer if he's on screen, ,not occluded, and "close enough" as defined by zoom level.
|
|
IF bOnScreen AND NOT bOccluded
|
|
FLOAT fScreenX, fScreenY
|
|
GET_HUD_SCREEN_POSITION_FROM_WORLD_POSITION(vDeerCoord, fScreenX, fScreenY)
|
|
IF (fScreenX > 0.3 AND fScreenX < 0.7 AND fScreenY > 0.3 AND fScreenY < 0.7)
|
|
AND (distToPlayer < fDistanceThreshold)
|
|
CPRINTLN(DEBUG_MISSION, "Removing any existing blip on elk before hard blipping.")
|
|
SAFE_REMOVE_BLIP(thisElk.mElkBlip)
|
|
ADD_SAFE_BLIP_TO_PED(thisElk.mElkBlip, thisElk.mPed, TRUE)
|
|
SET_BLIP_SHOW_CONE(thisElk.mElkBlip, TRUE)
|
|
thisElk.bHardBlipped = TRUE
|
|
|
|
TRIGGER_HUNTING_AUDIO("HUNTING_SPOT_ANIMAL")
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Adding hard blip on ELK. fDist: ", distToPlayer, ", Zoom: ", fZoomLevel, ", ScreenX: ", fScreenX, ", ScreenY: ", fScreenY)
|
|
EXIT
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// If the elk doesn't have a blip...
|
|
IF NOT DOES_BLIP_EXIST(thisElk.mElkBlip)
|
|
// There's a few cases in which the elk has to be blipped: making a call, or responfing to the player.
|
|
// Check response to the player.
|
|
IF (bPlayerCalling AND GET_GAME_TIMER() > iResponseTime AND NOT thisElk.bCalling) OR (thisElk.bCalling)
|
|
IF thisElk.bCalling
|
|
// Elk gets a radius blip.
|
|
FLOAT fBlipRadius = distToPlayer * 0.5
|
|
VECTOR vBlipPos = vDeerCoord
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Adding elk radius blip: ", fBlipRadius, " for elk: ", iElkIndex)
|
|
CPRINTLN(DEBUG_MISSION, "Deer at: ", vDeerCoord, " & player at: ", vHuntingPlayerCoords)
|
|
|
|
thisElk.mElkBlip = ADD_BLIP_FOR_RADIUS(vBlipPos/* + vBlipOffset*/, fBlipRadius)
|
|
SET_BLIP_ALPHA(thisElk.mElkBlip, 100)
|
|
SET_BLIP_COLOUR(thisElk.mElkBlip, BLIP_COLOUR_RED)
|
|
SHOW_HEIGHT_ON_BLIP(thisElk.mElkBlip, FALSE)
|
|
|
|
thisElk.iStartFadeTime = GET_GAME_TIMER() + 4000
|
|
ENDIF
|
|
|
|
IF (thisElk.bRandomlyCalls AND GET_GAME_TIMER() > iResponseTime)
|
|
OR bPlayerCalling
|
|
// If the elk is supposed to be calling, make it happen.
|
|
IF NOT thisElk.bCalling
|
|
// Delay us a bit.
|
|
IF (thisElk.iCallResponseTime = 0)
|
|
thisElk.iCallResponseTime = GET_GAME_TIMER() + (GET_RANDOM_INT_IN_RANGE(0, 11) * 100)
|
|
ELSE
|
|
IF (thisElk.iCallResponseTime < GET_GAME_TIMER())
|
|
thisElk.iCallResponseTime = 0
|
|
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_BREY_MASTER", thisElk.mPed)
|
|
CPRINTLN(DEBUG_MISSION, "Elk breying as a response to a call!")
|
|
thisElk.bCalling = TRUE
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
//CPRINTLN(DEBUG_MISSION,"Blip for this elk is visible = ", i)
|
|
IF DOES_BLIP_EXIST(thisElk.mElkBlip)
|
|
// Elk may be hard blipped, can still make calls.
|
|
IF (bPlayerCalling AND GET_GAME_TIMER() > iResponseTime AND NOT thisElk.bCalling)
|
|
CPRINTLN(DEBUG_MISSION, "Elk responding to another brey!")
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_BREY_MASTER", thisElk.mPed)
|
|
thisElk.bCalling = TRUE
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
EXIT
|
|
ENDIF
|
|
|
|
// So here, we only need to handle fading out.
|
|
IF (GET_GAME_TIMER() > thisElk.iStartFadeTime AND distToPlayer > 35 AND thisElk.bCanFadeBlip)
|
|
IF bOnScreen
|
|
// See if we need to shapetest for the blip.
|
|
IF (thisElk.iNextTestTime < GET_GAME_TIMER()
|
|
AND (iElkTesting = iElkIndex OR iElkTesting = -1))
|
|
AND (distToPlayer < fDistanceThreshold)
|
|
// Flag us as the tester!
|
|
iElkTesting = iElkIndex
|
|
|
|
INT iResult = RUN_SHAPE_TEST_FOR_ELK(thisElk, vDeerCoord, distToPlayer)
|
|
IF (iResult = 1)
|
|
// Passed!
|
|
IF thisElk.bHardBlipped
|
|
SET_BLIP_ALPHA(thisElk.mElkBlip, 255)
|
|
ELSE
|
|
SET_BLIP_ALPHA(thisElk.mElkBlip, 100)
|
|
ENDIF
|
|
thisElk.iStartFadeTime = GET_GAME_TIMER() + 10000
|
|
EXIT
|
|
|
|
ELIF (iResult = -1)
|
|
// Failed...
|
|
ELIF (iResult = 0)
|
|
// Continue processing...
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
thisElk.iBlipAlpha = GET_BLIP_ALPHA(thisElk.mElkBlip)
|
|
IF thisElk.iBlipAlpha > MIN_BLIP_ALPHA
|
|
IF GET_RANDOM_INT_IN_RANGE(0, 1000) > 666
|
|
thisElk.iBlipAlpha -= 1
|
|
//CPRINTLN(DEBUG_MISSION, "LOWERING BLIP ALPHA")
|
|
SET_BLIP_ALPHA(thisElk.mElkBlip, thisElk.iBlipAlpha)
|
|
ENDIF
|
|
ELSE
|
|
SET_BLIP_SHOW_CONE(thisElk.mElkBlip, FALSE)
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Elk blip alpha'd out. Removing.")
|
|
SAFE_REMOVE_BLIP(thisElk.mElkBlip)
|
|
thisElk.bHardBlipped = FALSE
|
|
thisElk.bCalling = FALSE
|
|
bPlayerCalling = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
PROC CHECK_FOR_CALLS()
|
|
IF NOT bAllowCall
|
|
//PRINTLN("CHECK_FOR_CALLS -- Calls disabled!")
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF NOT IS_PLAYER_PLAYING(PLAYER_ID())
|
|
PRINTLN("CHECK_FOR_CALLS -- Player not playing.")
|
|
EXIT
|
|
ENDIF
|
|
|
|
PED_INDEX playerPed = PLAYER_PED_ID()
|
|
IF GET_INTERIOR_FROM_ENTITY(playerPed) != NULL
|
|
PRINTLN("CHECK_FOR_CALLS -- Player in interior.")
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF DOES_ENTITY_EXIST(GET_VEHICLE_PED_IS_USING(playerPed))
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
|
|
EXIT
|
|
ENDIF
|
|
|
|
//PRINTLN("CHECK_FOR_CALLS -- Waiting for an elk call...")
|
|
IF (IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_SCRIPT_PAD_LEFT)
|
|
AND NOT IS_PLAYER_FREE_AIMING(PLAYER_ID())
|
|
AND NOT IS_PED_RAGDOLL(playerPed)
|
|
AND NOT IS_PED_RUNNING_RAGDOLL_TASK(playerPed))
|
|
OR (iWhistleDelay != -1)
|
|
PRINTLN("Processing a player whistle!")
|
|
|
|
// Allow player to call any time - as long as the last call isn't still playing...
|
|
IF GET_GAME_TIMER() > iWhistleCallTime
|
|
IF (iWhistleDelay = -1)
|
|
PRINTLN("Player started a whistle!")
|
|
// Start the timer.
|
|
iWhistleDelay = GET_GAME_TIMER() + 250
|
|
|
|
ELIF (GET_GAME_TIMER() > iWhistleDelay)
|
|
PRINTLN("Playing a player whistle.")
|
|
|
|
// Play the sound.
|
|
IF GET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT) <> CAM_VIEW_MODE_FIRST_PERSON
|
|
TASK_PLAY_ANIM(playerPed, "facials@p_m_one@variations@elkcall", "mood_elkcal_1", DEFAULT, DEFAULT, DEFAULT, AF_SECONDARY)
|
|
ENDIF
|
|
PLAY_SOUND_FROM_ENTITY(-1, "PLAYER_CALLS_ELK_MASTER", playerPed)
|
|
TRIGGER_SONAR_BLIP(GET_ENTITY_COORDS(playerPed), 30, HUD_COLOUR_BLUEDARK)
|
|
iWhistleCallTime = GET_GAME_TIMER() + WHISTLE_CALL_TIME
|
|
|
|
Player_Hunt_Data.iKillsSinceElkCall = 0
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
iWhistleDelay = -1
|
|
|
|
// Reset all deer calls
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
|
|
// Only have response when elk are due to respond - probably need to rename this variable
|
|
IF NOT bPlayerCalling
|
|
iResponseTime = GET_GAME_TIMER() + RESPONSE_DELAY
|
|
iCallEndTime = GET_GAME_TIMER() + CALL_DURATION
|
|
bPlayerCalling = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// See if we should be forcing sonar.
|
|
IF (GET_GAME_TIMER() < iCallEndTime)
|
|
CPRINTLN(DEBUG_HUNTING, "Forcing sonar blips due to recent call.")
|
|
FORCE_SONAR_BLIPS_THIS_FRAME()
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
// Checks if a random node that's passed in is suitable for the Elk's new destintion
|
|
FUNC BOOL IS_NODE_OK_FOR_THIS_ELK(INT i, INT iNode)
|
|
|
|
//CPRINTLN(DEBUG_MISSION,"Randomly chosen node..")
|
|
|
|
IF bIsAmbient = FALSE
|
|
//CPRINTLN(DEBUG_MISSION,"... is no good as we're not ambient ")
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF iNode = mElk[i].iCurNode
|
|
OR iNode = mElk[i].iPrevNode
|
|
OR elkSpawn[iNode].bIsBooked
|
|
OR GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(mElk[i].mPed, elkSpawn[iNode].vCoord) > 50.0
|
|
//CPRINTLN(DEBUG_MISSION,"... is no good ")
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
//CPRINTLN(DEBUG_MISSION,"... is OK TO TRAVEL TO ")
|
|
|
|
RETURN TRUE
|
|
|
|
ENDFUNC
|
|
/// PURPOSE: Measures the distance from the Elk's current node to each other node in the network,
|
|
/// disregarding the current node, the Elk's previously visited node, any node that is booked by another elk.
|
|
/// RETURNS: The value of the closest suitable node.
|
|
FUNC INT FIND_BEST_CLOSEST_NODE(INT i)
|
|
|
|
FLOAT fCurDist = 0.0
|
|
FLOAT fShortestDist = 10000.0
|
|
INT iCounter = 0
|
|
INT iClosestNode = 0
|
|
|
|
REPEAT MAX_GRAZE_AREAS iCounter
|
|
IF iCounter <> mElk[i].iCurNode
|
|
AND iCounter <> mElk[i].iPrevNode
|
|
AND NOT elkSpawn[iCounter].bIsBooked
|
|
// Try to find the next closest...
|
|
fCurDist = GET_DISTANCE_BETWEEN_COORDS(elkSpawn[mElk[i].iCurNode].vCoord, elkSpawn[iCounter].vCoord, FALSE)
|
|
//CPRINTLN(DEBUG_MISSION,"NODE DISTANCE IS")
|
|
//PRINTFLOAT(fCurDist) PRINTNL()
|
|
|
|
IF fCurDist < fShortestDist
|
|
//CPRINTLN(DEBUG_MISSION,"WHICH IS CLOSER THAN THE LAST NODE WE CHECKED")
|
|
fShortestDist = fCurDist
|
|
iClosestNode = iCounter
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN iClosestNode
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks to see if there is an elk blip visable
|
|
/// RETURNS:
|
|
/// True if there is an elk blip visible on the radar
|
|
FUNC BOOL IS_ANY_ELK_BLIP_VISIBLE()
|
|
|
|
INT i = 0
|
|
REPEAT MAX_ELKS i
|
|
IF DOES_BLIP_EXIST(mElk[i].mElkBlip)
|
|
mElk[i].iBlipAlpha = GET_BLIP_ALPHA(mElk[i].mElkBlip)
|
|
IF mElk[i].iBlipAlpha > MIN_BLIP_ALPHA
|
|
RETURN TRUE
|
|
ENDIF
|
|
// ELSE
|
|
// IF DOES_BLIP_EXIST(mElk[i].mHintBlip)
|
|
// RETURN TRUE
|
|
// ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Sets the elk state to ES_CHECK_CAN_SPAWN which kicks the elk
|
|
/// state machine in to gear
|
|
PROC SPAWN_FIRST_ELK()
|
|
CPRINTLN(DEBUG_MISSION,"SPAWN FIRST ELK")
|
|
|
|
INT i = 0
|
|
REPEAT MAX_ELKS i
|
|
// There's a chance that we started with some elk. If this is the case, don't retask.
|
|
IF NOT DOES_ENTITY_EXIST(mElk[i].mPed)
|
|
CPRINTLN(DEBUG_MISSION,"CHECKING WE CAN SPAWN IN ELK NUMBER ", i)
|
|
mElk[i].elkState = ES_CHECK_CAN_SPAWN
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
PROC UNBOOK_EVERY_GRAZE_POS()
|
|
INT i
|
|
REPEAT MAX_GRAZE_AREAS i
|
|
elkSpawn[i].bIsBooked = FALSE
|
|
elkSpawn[i].iNextSpawnTime = 0
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Deletes any alive elk and puts the elk state in to ES_NULL
|
|
/// thereby stopping the state machine running
|
|
PROC REMOVE_ALL_ELK()
|
|
CPRINTLN(DEBUG_MISSION, "REMOVE_ALL_ELK")
|
|
|
|
UNBOOK_EVERY_GRAZE_POS()
|
|
|
|
INT i
|
|
REPEAT MAX_ELKS i
|
|
SAFE_REMOVE_BLIP(mElk[i].mElkBlip)
|
|
IF DOES_ENTITY_EXIST(mElk[i].mPed)
|
|
AND IS_ENTITY_A_MISSION_ENTITY(mElk[i].mPed)
|
|
DELETE_PED(mElk[i].mPed)
|
|
ENDIF
|
|
SAFE_REMOVE_BLIP(mElk[i].mElkBlip)
|
|
|
|
SET_ELK_SPOOKED(i, FALSE)
|
|
mElk[i].elkState = ES_NULL
|
|
mElk[i].iCallResponseTime = 0
|
|
ENDREPEAT
|
|
|
|
iDoeInPlay = 0
|
|
iElksInPlay = 0
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Checks if an entity was damaged by the sniper rifle.
|
|
/// PARAMS:
|
|
/// index - the entity to check
|
|
PROC CHECK_TARGET_DAMAGED_BY_RIFLE(ENTITY_INDEX index)
|
|
CPRINTLN(DEBUG_MISSION,"CHECKING TARGET ELK WEAPON DAMAGE")
|
|
|
|
// We generally don't care about most of this in ambient hunting.
|
|
IF DOES_ENTITY_EXIST(index) AND IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
CPRINTLN(DEBUG_MISSION,"ENTITY EXISTS.")
|
|
|
|
IF NOT bIsAmbient
|
|
|
|
CPRINTLN(DEBUG_MISSION,"NON AMBIENT KILL")
|
|
|
|
VECTOR pos = GET_ENTITY_COORDS(index)
|
|
IF IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, pos, 20)
|
|
CLEAR_PRINTS()
|
|
bPlayerKillElkIncorrectly = TRUE
|
|
CPRINTLN(DEBUG_MISSION,"Elk incorrectly killed by explosion")
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(index, PLAYER_PED_ID())
|
|
// Only sniper rifles and knives in Hunting.
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(index, WEAPONTYPE_SNIPERRIFLE)
|
|
CPRINTLN(DEBUG_MISSION,"Elk damaged by sniper rifle")
|
|
EXIT
|
|
ENDIF
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(index, WEAPONTYPE_KNIFE)
|
|
CPRINTLN(DEBUG_MISSION,"Elk damaged by knife")
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Anything else is wrong.
|
|
CPRINTLN(DEBUG_MISSION,"Elk damaged by incorrect weapon!")
|
|
CLEAR_PRINTS()
|
|
bPlayerKillElkIncorrectly = TRUE
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION,"AMBIENT KILL")
|
|
|
|
// However, in ambient, we do care if the player kills a doe!
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(index, PLAYER_PED_ID())
|
|
CPRINTLN(DEBUG_MISSION,"AMBIENT KILL BY PLAYER")
|
|
|
|
// // If there's a decorator on this elk tagging it as a doe, we're going to fail.
|
|
// IF DECOR_EXIST_ON(index, "doe_elk")
|
|
// bKilledDoe = DECOR_GET_BOOL(index, "doe_elk")
|
|
// ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// When the player is outside the snipe area this is called to check if the player shoots from
|
|
/// outside the area when the shouldnt be
|
|
/// PARAMS:
|
|
/// index - the entity to be checking
|
|
PROC CHECK_FOR_PLAYER_DAMAGE_WHEN_OUTSIDE_SHOOT(ENTITY_INDEX index)
|
|
IF DOES_ENTITY_EXIST(index)
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(index, PLAYER_PED_ID())
|
|
IF NOT IS_ENTITY_DEAD(index)
|
|
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(index)
|
|
bPlayerKillElkIncorrectly = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Checks to see if an animal spawn would be in front of the player, in a cone.
|
|
FUNC BOOL WOULD_POINT_BE_IN_FRONT_OF_PLAYER(VECTOR vPoint)
|
|
VECTOR vFwd = GET_ENTITY_FORWARD_VECTOR(PLAYER_PED_ID())
|
|
vFwd.z = 0.0
|
|
|
|
VECTOR vBetween = vPoint - GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
vBetween = NORMALISE_VECTOR(vBetween)
|
|
|
|
FLOAT fDot = DOT_PRODUCT_XY(vFwd, vBetween)
|
|
//CPRINTLN(DEBUG_MISSION, "Dot product of point is: ", fDot)
|
|
|
|
IF (fDot > 0.1)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Counts through all the graze points in order.
|
|
/// Checks if it's safe to spawn an elk there (far enough from player and out of sight)
|
|
/// Randomly decides if the suitable point can be returned as the elks spawn point
|
|
/// PARAMS:
|
|
/// i -
|
|
/// RETURNS:
|
|
/// A random int to be used as a spawn point for a new elk
|
|
FUNC INT GET_SPAWN_POS()
|
|
INT i = GET_RANDOM_INT_IN_RANGE(0, MAX_GRAZE_AREAS)
|
|
IF elkSpawn[i].bIsBooked
|
|
RETURN MAX_GRAZE_AREAS+1
|
|
ENDIF
|
|
|
|
IF NOT IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
// CWARNINGLN(DEBUG_HUNTING, "GET_SPAWN_POS returning default, NOT IS_PED_UNINJURED(PLAYER_PED_ID())")
|
|
RETURN MAX_GRAZE_AREAS+1
|
|
ENDIF
|
|
|
|
IF IS_SPHERE_VISIBLE(elkSpawn[i].vCoord, 4.0)
|
|
// CWARNINGLN(DEBUG_HUNTING, "GET_SPAWN_POS returning default, IS_SPHERE_VISIBLE(elkSpawn[i].vCoord, 4.0)")
|
|
RETURN MAX_GRAZE_AREAS+1
|
|
ENDIF
|
|
|
|
VECTOR vCamPos = GET_GAMEPLAY_CAM_COORD()
|
|
VECTOR vCamRot = GET_GAMEPLAY_CAM_ROT()
|
|
VECTOR vCamForward = ROTATE_VECTOR_ABOUT_Z( (<<0,1,0>>), vCamRot.z )
|
|
VECTOR vCamToCoord = elkSpawn[i].vCoord - vCamPos
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
DEBUG_RECORD_SPHERE("vCamPos", vCamPos, 0.5, (<<0, 0, 255>>) )
|
|
DEBUG_RECORD_LINE("vCamForward", vCamPos, vCamPos + vCamForward, (<<255, 0, 0>>), (<<0, 255, 0>>) )
|
|
DEBUG_RECORD_LINE("vCamToCoord", vCamPos, vCamPos + vCamToCoord, (<<255, 0, 0>>), (<<0, 0, 255>>) )
|
|
#ENDIF
|
|
|
|
FLOAT fDot = DOT_PRODUCT(vCamForward, vCamToCoord)
|
|
|
|
IF fDot > 0
|
|
// CWARNINGLN(DEBUG_HUNTING, "GET_SPAWN_POS returning default, fDot > 0, fDot = ", fDot, " vCamForward = ", vCamForward, " vCamRot = ", vCamRot, " vCamPos = ", vCamPos )
|
|
RETURN MAX_GRAZE_AREAS+1
|
|
ENDIF
|
|
|
|
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
FLOAT fDist = GET_DISTANCE_BETWEEN_COORDS(vPlayerPos, elkSpawn[i].vCoord)
|
|
|
|
IF fDist > MIN_SAFE_SPAWN_DIST OR IS_SCREEN_FADED_OUT()
|
|
//CPRINTLN(DEBUG_MISSION,"This pos is NOT visible ", i)
|
|
RETURN i
|
|
ENDIF
|
|
|
|
//CPRINTLN(DEBUG_MISSION,"Couldn't find a valid spawn...")
|
|
RETURN MAX_GRAZE_AREAS+1
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
///
|
|
/// PARAMS:
|
|
/// i -
|
|
/// elkstate -
|
|
PROC SETUP_ELK(MY_ELK & thisElk, ELK_STATE elkstate, BOOL bBlipFade = TRUE)
|
|
//CPRINTLN(DEBUG_MISSION,"SET UP ELK...")
|
|
|
|
IF DOES_ENTITY_EXIST(thisElk.mPed)
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(thisElk.mPed, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(thisElk.mPed, CA_USE_COVER, FALSE)
|
|
SET_PED_FLEE_ATTRIBUTES(thisElk.mPed, FA_USE_COVER, FALSE)
|
|
SET_ENTITY_HEALTH(thisElk.mPed, 100)
|
|
SET_PED_BLOCKS_PATHING_WHEN_DEAD(thisElk.mPed, TRUE)
|
|
|
|
SET_PED_RELATIONSHIP_GROUP_HASH(thisElk.mPed, mElkGroup)
|
|
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_HATE, mElkGroup, RELGROUPHASH_PLAYER)
|
|
|
|
SET_PED_SEEING_RANGE(thisElk.mPed, SIGHT_RANGE_DUCKED)
|
|
SET_PED_HEARING_RANGE(thisElk.mPed, HEAR_RANGE)
|
|
|
|
SET_ENTITY_LOD_DIST(thisElk.mPed, 1500)
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(thisElk.mPed, TRUE)
|
|
SET_PED_LOD_MULTIPLIER(thisElk.mPed, 5.0)
|
|
SET_PED_CAN_BE_TARGETTED(thisElk.mPed, FALSE)
|
|
|
|
thisElk.iNumFollowers = 0
|
|
thisElk.bRandomlyCalls = TRUE
|
|
thisElk.bHardBlipped = FALSE
|
|
thisElk.bCanFadeBlip = bBlipFade
|
|
thisElk.bIsSpooked = FALSE
|
|
//CPRINTLN(DEBUG_MISSION,"Set Up Elk - bIsSpooked = FALSE")
|
|
IF bIsAmbient AND NOT thisElk.bIsHerdMember
|
|
elkSpawn[thisElk.iCurNode].bIsBooked = TRUE
|
|
elkSpawn[thisElk.iCurNode].iNextSpawnTime = GET_GAME_TIMER() + ELK_SPAWN_RESPAWN_DELAY
|
|
ENDIF
|
|
//CPRINTLN(DEBUG_MISSION,"Set up Elk - Booking graze node", mElk[i].iCurNode)
|
|
bUncleanKill = FALSE
|
|
|
|
iElksInPlay++
|
|
//CPRINTLN(DEBUG_MISSION,"Set up Elk - iElksInPlay has been incremented = ", iElksInPlay)
|
|
|
|
thisElk.elkState = elkstate
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
///
|
|
/// PARAMS:
|
|
/// i -
|
|
/// RETURNS:
|
|
///
|
|
FUNC BOOL SPAWN_ELK(INT i, ELK_STATE elkstate, BOOL bRandSpawn = TRUE, BOOL bBlipFade = TRUE)
|
|
IF bRandSpawn AND bIsAmbient
|
|
INT iSpawn = GET_SPAWN_POS()
|
|
IF iSpawn > MAX_GRAZE_AREAS
|
|
RETURN FALSE
|
|
ELSE
|
|
// If this spawn point would be more than 150m away, we can't spawn here.
|
|
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), elkSpawn[iSpawn].vCoord) > 22500.0
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// If we've spawned too recently, we can't spawn there again.
|
|
IF GET_GAME_TIMER() < elkSpawn[iSpawn].iNextSpawnTime
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
//CPRINTLN(DEBUG_MISSION,"Chosen spawn is position ", iSpawn)
|
|
VECTOR vCoord = GET_RANDOM_POINT_IN_SPHERE(elkSpawn[iSpawn].vCoord, 5.0)
|
|
GET_GROUND_Z_FOR_3D_COORD(vCoord + (<<0.0,0.5,0.0>>), vCoord.z)
|
|
mElk[i].vPos = vCoord
|
|
mElk[i].iCurNode = iSpawn
|
|
SET_ELK_SPOOKED(i, FALSE)
|
|
IF bIsAmbient
|
|
elkSpawn[iSpawn].bIsBooked = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// We'll always pick a random spanw heading.
|
|
mElk[i].fRandHead = GET_RANDOM_FLOAT_IN_RANGE(0.0, 359.9)
|
|
|
|
// Try and spawn the elk.
|
|
IF SETUP_PED(mElk[i].mPed, mElk[i].vPos, mElk[i].fRandHead, mElk[i].mModel, FALSE)
|
|
SETUP_ELK(mElk[i], elkstate, bBlipFade)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Spawns an addition elk as a member of a static herd.
|
|
/// PARAMS:
|
|
/// pedLeadElk - This is the main elk where all the others are placed near.
|
|
/// i -
|
|
/// eElkHerdPos - The relative position of the elk.
|
|
/// elkstate - The state
|
|
/// bBlipFade -
|
|
/// bIsStatic -
|
|
/// RETURNS:
|
|
///
|
|
///
|
|
|
|
|
|
FUNC BOOL SPAWN_ELK_HERD_MEMBER(INT i, INT iLeadElkIndex)
|
|
IF IS_PED_UNINJURED( mElk[iLeadElkIndex].mPed )
|
|
VECTOR vOffset
|
|
VECTOR vPos = GET_ENTITY_COORDS(mElk[iLeadElkIndex].mPed)
|
|
FLOAT fHeading = GET_ENTITY_HEADING(mElk[iLeadElkIndex].mPed)
|
|
|
|
SWITCH i
|
|
// Offset on left flank
|
|
CASE HERD_MEMBER_LEFT
|
|
vOffset = << GET_RANDOM_FLOAT_IN_RANGE( -3.0, -2.0 ), GET_RANDOM_FLOAT_IN_RANGE( -2.0, -2.0 ), 0.0 >>
|
|
BREAK
|
|
|
|
// Offset on right flank
|
|
CASE HERD_MEMBER_RIGHT
|
|
vOffset = << GET_RANDOM_FLOAT_IN_RANGE( 3.0, 2.0 ), GET_RANDOM_FLOAT_IN_RANGE( -2.0, -2.0 ), 0.0 >>
|
|
BREAK
|
|
|
|
// Offset to the front
|
|
CASE HERD_MEMBER_FRONT
|
|
vOffset = << GET_RANDOM_FLOAT_IN_RANGE( -2.0, 2.0 ), GET_RANDOM_FLOAT_IN_RANGE( 2.0, 3.0 ), 0.0 >>
|
|
BREAK
|
|
|
|
// Offset to the rear
|
|
CASE HERD_MEMBER_REAR
|
|
vOffset = << GET_RANDOM_FLOAT_IN_RANGE( -2.0, 2.0 ), GET_RANDOM_FLOAT_IN_RANGE( -3.0, -2.0 ), 0.0 >>
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
mElk[i].vPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, vOffset)
|
|
SNAP_3D_COORD_TO_GROUND(mElk[i].vPos)
|
|
mElk[i].fRandHead = fHeading + GET_RANDOM_FLOAT_IN_RANGE(-30.0, 30.0)
|
|
mElk[i].iCurNode = mElk[iLeadElkIndex].iCurNode
|
|
SET_ELK_SPOOKED(i, FALSE)
|
|
mElk[i].bIsHerdMember = TRUE
|
|
mElk[i].iLeaderIdx = iLeadElkIndex
|
|
|
|
// Mark our leader as a leader.
|
|
mElk[iLeadElkIndex].bIsHerdLeader = TRUE
|
|
|
|
WHILE mElk[i].fRandHead < -180.0
|
|
mElk[i].fRandHead += 360.0
|
|
ENDWHILE
|
|
WHILE mElk[i].fRandHead > 180.0
|
|
mElk[i].fRandHead -= 360.0
|
|
ENDWHILE
|
|
|
|
CPRINTLN( DEBUG_MISSION, "Elk Heading:", mElk[i].fRandHead )
|
|
|
|
// If the lead elk already has a follower, force a doe elk.
|
|
BOOL bForceDoe = FALSE
|
|
IF (mElk[iLeadElkIndex].iNumFollowers != 0)
|
|
bForceDoe = TRUE
|
|
ENDIF
|
|
|
|
IF SETUP_PED(mElk[i].mPed, mElk[i].vPos, mElk[i].fRandHead, mElk[i].mModel, FALSE, bForceDoe)
|
|
SETUP_ELK(mElk[i], ES_GRAZE, TRUE)
|
|
TASK_FOLLOW_TO_OFFSET_OF_ENTITY(mElk[i].mPed, mElk[iLeadElkIndex].mPed, vOffset, PEDMOVEBLENDRATIO_WALK)
|
|
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC HIT_LOCATION GET_HIT_LOCATION_FOR_ELK_BONE_ID(INT iBoneID)
|
|
SWITCH (iBoneID)
|
|
CASE 31086 // Head
|
|
CASE 65079 // AntlerRoot
|
|
RETURN HL_HEAD
|
|
BREAK
|
|
|
|
CASE 39317 // Neck1
|
|
CASE 24532 // Neck2
|
|
RETURN HL_NECK
|
|
BREAK
|
|
|
|
CASE 45509 // L_UpperArm
|
|
CASE 40269 // R_UpperArm
|
|
CASE 24818 // Spine3
|
|
CASE 24816 // Spine1
|
|
CASE 64729 // L_Clavicle
|
|
CASE 10706 // R_Clavicle
|
|
RETURN HL_HEART
|
|
BREAK
|
|
|
|
CASE 61163 // L_Forearm
|
|
CASE 26610 // L_Finger00
|
|
CASE 4089 // L_Finger01
|
|
CASE 18905 // L_Hand
|
|
CASE 37709 // PH_L_Hand
|
|
CASE 36029 // IK_L_Hand
|
|
CASE 28252 // R_Forearm
|
|
CASE 58866 // R_Finger00
|
|
CASE 64016 // R_Finger01
|
|
CASE 57005 // R_Hand
|
|
CASE 7966 // PH_R_Hand
|
|
CASE 6286 // IK_R_Hand
|
|
RETURN HL_FORELEG
|
|
BREAK
|
|
|
|
CASE 63931 // L_Calf
|
|
CASE 14201 // L_Foot
|
|
CASE 2108 // L_Toe0
|
|
CASE 7531 // L_Toe1
|
|
CASE 2718 // PH_L_Foot
|
|
CASE 65245 // IK_L_Foot
|
|
CASE 36864 // R_Calf
|
|
CASE 52301 // R_Foot
|
|
CASE 20781 // R_Toe0
|
|
CASE 45631 // R_Toe1
|
|
CASE 38142 // PH_R_Foot
|
|
CASE 35502 // IK_R_Foot
|
|
RETURN HL_HINDLEG
|
|
BREAK
|
|
|
|
CASE 11816 // Pelvis
|
|
CASE 58271 // L_Thigh
|
|
CASE 51826 // R_Thigh
|
|
CASE 839 // Tail_01
|
|
CASE 840 // Tail_02
|
|
CASE 841 // Tail_03
|
|
CASE 842 // Tail_04
|
|
CASE 843 // Tail_05
|
|
RETURN HL_ASS
|
|
BREAK
|
|
|
|
CASE 0 // Root
|
|
CASE 57597 // Spine_Root
|
|
CASE 23553 // Spine0
|
|
CASE 24817 // Spine2
|
|
CASE 17916 // PelvisRoot
|
|
CASE 53251 // Pelvis1
|
|
RETURN HL_BODY
|
|
BREAK
|
|
|
|
ENDSWITCH
|
|
// We should never get here. All bones were accounted for that were listed in:
|
|
// x:\gta5\tools\etc\config\anim\skeletons\deer.skel
|
|
RETURN HL_BODY
|
|
ENDFUNC
|
|
|
|
|
|
// Get the last damaged bonetag and saves that out to the player_hunt_data_struct ehitLocation.
|
|
// Svaes the screen position of where the x should go
|
|
PROC RECORD_LAST_HIT_LOCATION(INT iElk)
|
|
PED_BONETAG ePedBoneTag
|
|
GET_PED_LAST_DAMAGE_BONE(mElk[iElk].mPed, ePedBoneTag)
|
|
INT iBoneID = ENUM_TO_INT(ePedBoneTag)
|
|
|
|
HIT_LOCATION hitLoc = GET_HIT_LOCATION_FOR_ELK_BONE_ID(iBoneID)
|
|
Player_Hunt_Data.iHitsOnLocation[hitLoc]++
|
|
IF hitLoc = HL_HEART
|
|
Player_Hunt_Data.iKillStreakHeartshot++
|
|
ELSE
|
|
Player_Hunt_Data.iKillStreakHeartshot = 0
|
|
ENDIF
|
|
|
|
// No matter what, delay the challenge update.
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
ENDPROC
|
|
|
|
|
|
PROC SCORE_NOTIFICATION( string sText, INT iScore)
|
|
TEXT_LABEL_15 txtNotification = "HN_ELK"
|
|
IF iScore = 1
|
|
txtNotification += "_1PT"
|
|
ENDIF
|
|
BEGIN_TEXT_COMMAND_THEFEED_POST( txtNotification )
|
|
ADD_TEXT_COMPONENT_SUBSTRING_TEXT_LABEL( sText )
|
|
ADD_TEXT_COMPONENT_INTEGER( iScore )
|
|
END_TEXT_COMMAND_THEFEED_POST_TICKER(FALSE)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Registers a lootable corpse within the system.
|
|
PROC ADD_CORPSE_WITH_LOCATION(ENTITY_INDEX entLootable, KILL_TYPE eKillType, WEAPON_TYPE eKillWeapon)
|
|
// TEMP: Looting can't be done in MP.
|
|
//IF NETWORK_IS_IN_SESSION()
|
|
// EXIT
|
|
//ENDIF
|
|
|
|
IF NOT DOES_ENTITY_EXIST(entLootable)
|
|
// CERRORLN(DEBUG_LOOTING, "ADD_LOOTABLE_CORPSE - Cannot add invalid entity to the looting system.")
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF IS_IN_ITEMSET(entLootable, Player_Hunt_data.setCorpses)
|
|
// CDEBUG3LN(DEBUG_LOOTING, "ADD_LOOTABLE_CORPSE - Corpse already exists in the lootable set..")
|
|
EXIT
|
|
ENDIF
|
|
|
|
// IF NOT GET_ENTITY_LOOTABLE(entLootable)
|
|
// CDEBUG3LN(DEBUG_LOOTING, "ADD_LOOTABLE_CORPSE - Entity not lootable.")
|
|
// EXIT
|
|
// ENDIF
|
|
DECOR_SET_INT(entLootable, "hunt_score", ENUM_TO_INT(eKillType))
|
|
|
|
IF Player_Hunt_Data.iKillsSinceSpooked > 0
|
|
DECOR_SET_BOOL(entLootable, "hunt_undetected", TRUE)
|
|
ENDIF
|
|
IF Player_Hunt_Data.iKillsSinceElkCall > 0
|
|
DECOR_SET_BOOL(entLootable, "hunt_nocall", TRUE)
|
|
ENDIF
|
|
IF IS_WEAPON_VALID(eKillWeapon)
|
|
DECOR_SET_INT(entLootable, "hunt_weapon", ENUM_TO_INT(eKillWeapon))
|
|
ENDIF
|
|
|
|
// Add decorators so Cletus knows to comment on this one!
|
|
IF Player_Hunt_Data.challengeData[HC_WEAPONS_MASTER].hcRank = HCR_RANK_2
|
|
IF eKillType = KILL_BOAR_KILL AND eKillWeapon = WEAPONTYPE_RUNOVERBYVEHICLE
|
|
DECOR_SET_INT(entLootable, "hunt_chal_weapon", 2)
|
|
ENDIF
|
|
ELIF Player_Hunt_Data.challengeData[HC_WEAPONS_MASTER].hcRank = HCR_RANK_1
|
|
IF eKillType = KILL_COYOTE_KILL AND (eKillWeapon = WEAPONTYPE_PUMPSHOTGUN OR eKillWeapon = WEAPONTYPE_SAWNOFFSHOTGUN OR eKillWeapon = WEAPONTYPE_ASSAULTSHOTGUN)
|
|
DECOR_SET_INT(entLootable, "hunt_chal_weapon", 1)
|
|
ENDIF
|
|
ELIF Player_Hunt_Data.challengeData[HC_WEAPONS_MASTER].hcRank = HCR_RANK_3
|
|
IF eKillType = KILL_MOUNTAIN_LION_KILL AND (eKillWeapon = WEAPONTYPE_GRENADELAUNCHER OR eKillWeapon = WEAPONTYPE_RPG OR eKillWeapon = WEAPONTYPE_GRENADE)
|
|
DECOR_SET_INT(entLootable, "hunt_chal_weapon", 3)
|
|
ENDIF
|
|
ELIF Player_Hunt_Data.challengeData[HC_WEAPONS_MASTER].hcRank = HCR_RANK_4
|
|
IF eKillType < KILL_DOE_KILL AND (eKillWeapon = WEAPONTYPE_SNIPERRIFLE OR eKillWeapon = WEAPONTYPE_HEAVYSNIPER)
|
|
IF NOT IS_FIRST_PERSON_AIM_CAM_ACTIVE()
|
|
DECOR_SET_INT(entLootable, "hunt_chal_weapon", 4)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Put that entity within the looting system.
|
|
// CDEBUG2LN(DEBUG_LOOTING, "ADD_LOOTABLE_CORPSE - Adding a lootable corpse!")
|
|
DECOR_SET_INT(entLootable, "hunt_kill_time", GET_GAME_TIMER())
|
|
IF NOT IS_IN_ITEMSET(entLootable, Player_Hunt_data.setCorpses)
|
|
ADD_TO_ITEMSET(entLootable, Player_Hunt_data.setCorpses)
|
|
ENDIF
|
|
SET_ENTITY_AS_MISSION_ENTITY(entLootable)
|
|
PED_INDEX pedCorpse = GET_PED_INDEX_FROM_ENTITY_INDEX(entLootable)
|
|
SET_PED_CONFIG_FLAG(pedCorpse, PCF_RemoveDeadExtraFarAway, TRUE)
|
|
Player_Hunt_data.bSentPhotoHelp = FALSE // Send a text!
|
|
Player_Hunt_data.bSentPhotoNearHelp = FALSE // Send a text!
|
|
Player_Hunt_data.bSentPhotoSendHelp = FALSE // Send a text!
|
|
|
|
|
|
// PRINTLN("Added corpse ", NATIVE_TO_INT(entLootable), " at dist ", VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(entLootable)))
|
|
|
|
ENDPROC
|
|
|
|
|
|
|
|
PROC ADD_CLEAN_KILL_CORPSE(INT i)
|
|
PED_BONETAG ePedBoneTag
|
|
GET_PED_LAST_DAMAGE_BONE(mElk[i].mPed, ePedBoneTag)
|
|
INT iBoneID = ENUM_TO_INT(ePedBoneTag)
|
|
KILL_TYPE eKillType
|
|
HIT_LOCATION hitLoc = GET_HIT_LOCATION_FOR_ELK_BONE_ID(iBoneID)
|
|
|
|
SWITCH (hitLoc)
|
|
CASE HL_HEAD
|
|
CPRINTLN(DEBUG_MISSION,"Increase score HEAD: ", iBoneID)
|
|
eKillType = KILL_HEAD_SHOT
|
|
BREAK
|
|
|
|
CASE HL_NECK
|
|
CPRINTLN(DEBUG_MISSION,"Increase score NECK: ", iBoneID)
|
|
eKillType = KILL_NECK_SHOT
|
|
BREAK
|
|
|
|
CASE HL_HEART
|
|
CPRINTLN(DEBUG_MISSION,"Increase score HEART: ", iBoneID)
|
|
eKillType = KILL_HEART_SHOT
|
|
BREAK
|
|
|
|
CASE HL_HINDLEG
|
|
CASE HL_FORELEG
|
|
CPRINTLN(DEBUG_MISSION,"Increase score FRONT LEG: ", iBoneID)
|
|
eKillType = KILL_LEG_SHOT
|
|
BREAK
|
|
|
|
CASE HL_ASS
|
|
CPRINTLN(DEBUG_MISSION,"Increase score REAR: ", iBoneID)
|
|
eKillType = KILL_ASS_SHOT
|
|
BREAK
|
|
|
|
CASE HL_BODY
|
|
CPRINTLN(DEBUG_MISSION,"Increase score TORSO: ", iBoneID)
|
|
eKillType = KILL_TORSO_SHOT
|
|
BREAK
|
|
|
|
DEFAULT
|
|
// We should never get here. All bones were accounted for that were listed in:
|
|
// x:\gta5\tools\etc\config\anim\skeletons\deer.skel
|
|
CPRINTLN(DEBUG_MISSION, "================= INCREASE_SCORE - Unknown Bone: ", iBoneID, " =================")
|
|
eKillType = KILL_TORSO_SHOT
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
IF IS_ELK_A_DOE(mElk[i].mPed)
|
|
eKillType = KILL_DOE_KILL
|
|
ENDIF
|
|
WEAPON_TYPE killWeapon
|
|
IF NOT GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), killWeapon)
|
|
killWeapon = WEAPONTYPE_INVALID
|
|
ENDIF
|
|
ADD_CORPSE_WITH_LOCATION(mElk[i].mPed, eKillType, killWeapon)
|
|
|
|
ENDPROC
|
|
|
|
|
|
///// PURPOSE:
|
|
///// Makes trevor utter a random line when he kills an elk.
|
|
//PROC HANDLE_KILL_DIALOGUE()
|
|
// IF bIsAmbient
|
|
// IF GET_RANDOM_BOOL() AND (iNextDialogueTime < GET_GAME_TIMER())
|
|
// CPRINTLN(DEBUG_MISSION,"HANDLE_KILL_DIALOGUE - Showing Dialoge")
|
|
// CREATE_CONVERSATION(mTrevConv, sTrevText, "HTAMB_RAND", CONV_PRIORITY_MEDIUM)
|
|
//
|
|
// // Sets our next dialogue time to be in the future.
|
|
// iNextDialogueTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(MIN_DIALOGUE_DELAY_TIME, MAX_DIALOGUE_DELAY_TIME)
|
|
// ENDIF
|
|
// ENDIF
|
|
//ENDPROC
|
|
|
|
|
|
|
|
|
|
PROC CHECK_WEAPONS_MASTER_CHALLENGE_FOR_ANIMAL(HT_PLAYER_DATA &huntingData, ENTITY_INDEX entAnimal)
|
|
IF huntingData.challengeData[HC_WEAPONS_MASTER].hcStatus != HCS_RANK_UPDATE
|
|
EXIT
|
|
ENDIF
|
|
MODEL_NAMES modelName
|
|
SWITCH huntingData.challengeData[HC_WEAPONS_MASTER].hcRank
|
|
CASE HCR_RANK_1
|
|
IF GET_ENTITY_MODEL(entAnimal) != A_C_COYOTE
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_PUMPSHOTGUN)
|
|
OR HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_SAWNOFFSHOTGUN)
|
|
OR HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_ASSAULTSHOTGUN)
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
Player_Hunt_Data.bChallengeScreenSetup = FALSE
|
|
huntingData.challengeData[HC_WEAPONS_MASTER].hcStatus = HCS_RANK_COMPLETE_TOAST
|
|
ENDIF
|
|
BREAK
|
|
CASE HCR_RANK_2
|
|
IF GET_ENTITY_MODEL(entAnimal) != A_C_BOAR
|
|
EXIT
|
|
ENDIF
|
|
|
|
//PED_INDEX pedAnimal
|
|
//pedAnimal = GET_PED_INDEX_FROM_ENTITY_INDEX(entAnimal)
|
|
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND HAS_PED_BEEN_DAMAGED_BY_WEAPON(GET_PED_INDEX_FROM_ENTITY_INDEX(entAnimal), WEAPONTYPE_RUNOVERBYVEHICLE)
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
Player_Hunt_Data.bChallengeScreenSetup = FALSE
|
|
huntingData.challengeData[HC_WEAPONS_MASTER].hcStatus = HCS_RANK_COMPLETE_TOAST
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE HCR_RANK_3
|
|
IF GET_ENTITY_MODEL(entAnimal) != A_C_MTLION
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_GRENADELAUNCHER)
|
|
OR HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_RPG)
|
|
OR HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_GRENADE)
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
Player_Hunt_Data.bChallengeScreenSetup = FALSE
|
|
huntingData.challengeData[HC_WEAPONS_MASTER].hcStatus = HCS_RANK_COMPLETE_TOAST
|
|
ENDIF
|
|
BREAK
|
|
CASE HCR_RANK_4
|
|
IF GET_ENTITY_MODEL(entAnimal) != A_C_DEER
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_SNIPERRIFLE)
|
|
OR HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_HEAVYSNIPER)
|
|
IF NOT IS_FIRST_PERSON_AIM_CAM_ACTIVE() AND NOT IS_ELK_A_DOE(entAnimal)
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
Player_Hunt_Data.bChallengeScreenSetup = FALSE
|
|
huntingData.challengeData[HC_WEAPONS_MASTER].hcStatus = HCS_RANK_COMPLETE_TOAST
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
CASE HCR_RANK_5
|
|
modelName = GET_ENTITY_MODEL(entAnimal)
|
|
IF modelName != A_C_CHICKENHAWK
|
|
AND modelName != A_C_CORMORANT
|
|
AND modelName != A_C_CROW
|
|
AND modelName != A_C_PIGEON
|
|
AND modelName != A_C_SEAGULL
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_SNIPERRIFLE)
|
|
OR HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( entAnimal, WEAPONTYPE_HEAVYSNIPER)
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
Player_Hunt_Data.bChallengeScreenSetup = FALSE
|
|
huntingData.challengeData[HC_WEAPONS_MASTER].hcStatus = HCS_RANK_COMPLETE_TOAST
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
PROC MARK_ELK_KILL_TIME()
|
|
INT iElkTimeIndex
|
|
REPEAT COUNT_OF(Player_Hunt_Data.iKillTimes) iElkTimeIndex
|
|
IF Player_Hunt_Data.iKillTimes[iElkTimeIndex] = 0
|
|
Player_Hunt_Data.iKillTimes[iElkTimeIndex] = GET_GAME_TIMER()
|
|
EXIT
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
|
|
FUNC INT GET_SCORE_FOR_KILL_TYPE(KILL_TYPE eKillType)
|
|
SWITCH eKillType
|
|
CASE KILL_HEART_SHOT RETURN SCORE_HEART_SHOT
|
|
CASE KILL_HEAD_SHOT RETURN SCORE_HEAD_SHOT
|
|
CASE KILL_NECK_SHOT RETURN SCORE_NECK_SHOT
|
|
CASE KILL_TORSO_SHOT RETURN SCORE_TORSO_SHOT
|
|
CASE KILL_ASS_SHOT RETURN SCORE_ASS_SHOT
|
|
CASE KILL_LEG_SHOT RETURN SCORE_LEG_SHOT
|
|
CASE KILL_SPOOKED_SHOT RETURN SCORE_SPOOKED_SHOT
|
|
CASE KILL_ROAD_KILL RETURN SCORE_ROAD_KILL
|
|
CASE KILL_MOUNTAIN_LION_KILL RETURN SCORE_MOUNTAIN_LION_KILL
|
|
CASE KILL_BOAR_KILL RETURN SCORE_BOAR_KILL
|
|
CASE KILL_COYOTE_KILL RETURN SCORE_COYOTE_KILL
|
|
CASE KILL_BIRD_KILL RETURN SCORE_BIRD_KILL
|
|
CASE KILL_HUMAN_KILL RETURN SCORE_HUMAN_KILL
|
|
ENDSWITCH
|
|
RETURN 0
|
|
ENDFUNC
|
|
|
|
FUNC INT GET_MONEY_FOR_KILL_TYPE(KILL_TYPE eKillType)
|
|
SWITCH eKillType
|
|
CASE KILL_HEART_SHOT RETURN MONEY_HEART_SHOT
|
|
CASE KILL_HEAD_SHOT RETURN MONEY_HEAD_SHOT
|
|
CASE KILL_NECK_SHOT RETURN MONEY_NECK_SHOT
|
|
CASE KILL_TORSO_SHOT RETURN MONEY_TORSO_SHOT
|
|
CASE KILL_ASS_SHOT RETURN MONEY_ASS_SHOT
|
|
CASE KILL_LEG_SHOT RETURN MONEY_LEG_SHOT
|
|
CASE KILL_SPOOKED_SHOT RETURN MONEY_SPOOKED_SHOT
|
|
CASE KILL_ROAD_KILL RETURN MONEY_ROAD_KILL
|
|
CASE KILL_DOE_KILL RETURN MONEY_DOE
|
|
CASE KILL_MOUNTAIN_LION_KILL RETURN MONEY_MOUNTAIN_LION_KILL
|
|
CASE KILL_BOAR_KILL RETURN MONEY_BOAR_KILL
|
|
CASE KILL_COYOTE_KILL RETURN MONEY_COYOTE_KILL
|
|
CASE KILL_BIRD_KILL RETURN MONEY_BIRD_KILL
|
|
CASE KILL_HUMAN_KILL RETURN MONEY_HUMAN_KILL
|
|
ENDSWITCH
|
|
RETURN 0
|
|
ENDFUNC
|
|
|
|
FUNC FLOAT GET_MONEY_MULTIPLIER_FOR_WEAPONGROUP(WEAPON_GROUP eWeaponGroup)
|
|
SWITCH eWeaponGroup
|
|
CASE WEAPONGROUP_MELEE RETURN MONEY_MULT_MELEE
|
|
CASE WEAPONGROUP_PISTOL RETURN MONEY_MULT_PISTOL
|
|
CASE WEAPONGROUP_SMG RETURN MONEY_MULT_SMG
|
|
CASE WEAPONGROUP_RIFLE RETURN MONEY_MULT_RIFLE
|
|
CASE WEAPONGROUP_MG RETURN MONEY_MULT_MG
|
|
CASE WEAPONGROUP_SHOTGUN RETURN MONEY_MULT_SHOTGUN
|
|
CASE WEAPONGROUP_SNIPER RETURN MONEY_MULT_SNIPER
|
|
CASE WEAPONGROUP_HEAVY RETURN MONEY_MULT_HEAVY
|
|
CASE WEAPONGROUP_THROWN RETURN MONEY_MULT_THROWN
|
|
ENDSWITCH
|
|
RETURN MONEY_MULT_MELEE
|
|
ENDFUNC
|
|
|
|
FUNC STRING GET_NOTIFICATION_FOR_KILL_TYPE(KILL_TYPE eKillType)
|
|
SWITCH eKillType
|
|
CASE KILL_HEART_SHOT RETURN "HN_HT"
|
|
CASE KILL_HEAD_SHOT RETURN "HN_HS"
|
|
CASE KILL_NECK_SHOT RETURN "HN_NS"
|
|
CASE KILL_TORSO_SHOT RETURN "HN_TS"
|
|
CASE KILL_ASS_SHOT RETURN "HN_REAR"
|
|
CASE KILL_LEG_SHOT RETURN "HN_FL"
|
|
CASE KILL_SPOOKED_SHOT RETURN "HN_SPK"
|
|
CASE KILL_ROAD_KILL RETURN "HN_RDK"
|
|
CASE KILL_DOE_KILL RETURN "HN_DOE"
|
|
CASE KILL_MOUNTAIN_LION_KILL RETURN "HN_MLK"
|
|
CASE KILL_BOAR_KILL RETURN "HN_BRK"
|
|
CASE KILL_COYOTE_KILL RETURN "HN_CYK"
|
|
CASE KILL_BIRD_KILL RETURN "HN_BDK"
|
|
CASE KILL_HUMAN_KILL RETURN "HN_HMK"
|
|
ENDSWITCH
|
|
RETURN ""
|
|
ENDFUNC
|
|
|
|
FUNC TEXT_LABEL GET_HUNTING_TEXT_VARIATION(STRING strBase, INT iVariations)
|
|
TEXT_LABEL retVal = "HTXT_"
|
|
retVal += strBase
|
|
|
|
IF iVariations != 0
|
|
retVal += GET_RANDOM_INT_IN_RANGE(1,iVariations+1)
|
|
ENDIF
|
|
RETURN retVal
|
|
ENDFUNC
|
|
|
|
FUNC TEXT_LABEL GET_TEXT_MESSAGE_FOR_KILL_TYPE(KILL_TYPE eKillType)
|
|
SWITCH eKillType
|
|
CASE KILL_HEART_SHOT RETURN GET_HUNTING_TEXT_VARIATION("HT", 5)
|
|
CASE KILL_HEAD_SHOT RETURN GET_HUNTING_TEXT_VARIATION("HS", 5)
|
|
CASE KILL_NECK_SHOT RETURN GET_HUNTING_TEXT_VARIATION("NS", 5)
|
|
CASE KILL_TORSO_SHOT RETURN GET_HUNTING_TEXT_VARIATION("TS", 5)
|
|
CASE KILL_ASS_SHOT RETURN GET_HUNTING_TEXT_VARIATION("REAR", 5)
|
|
CASE KILL_LEG_SHOT RETURN GET_HUNTING_TEXT_VARIATION("RL", 5)
|
|
CASE KILL_SPOOKED_SHOT RETURN GET_HUNTING_TEXT_VARIATION("SPK", 5)
|
|
CASE KILL_DOE_KILL RETURN GET_HUNTING_TEXT_VARIATION("DOE", 5)
|
|
CASE KILL_ROAD_KILL RETURN GET_HUNTING_TEXT_VARIATION("RDK", 3)
|
|
CASE KILL_MOUNTAIN_LION_KILL RETURN GET_HUNTING_TEXT_VARIATION("MLK", 3)
|
|
CASE KILL_BOAR_KILL RETURN GET_HUNTING_TEXT_VARIATION("BRK", 3)
|
|
CASE KILL_COYOTE_KILL RETURN GET_HUNTING_TEXT_VARIATION("CYK", 3)
|
|
CASE KILL_BIRD_KILL RETURN GET_HUNTING_TEXT_VARIATION("BDK", 3)
|
|
CASE KILL_HUMAN_KILL RETURN GET_HUNTING_TEXT_VARIATION("HMK", 3)
|
|
CASE KILL_LIVE_ANIMAL RETURN GET_HUNTING_TEXT_VARIATION("LIVE", 3)
|
|
ENDSWITCH
|
|
RETURN GET_HUNTING_TEXT_VARIATION("GEN", 0)
|
|
ENDFUNC
|
|
|
|
FUNC TEXT_LABEL GET_TEXT_MESSAGE_FOR_KILL(ITEM_INDEX itemKillCorpse, KILL_TYPE eKillType, WEAPON_TYPE eKillWeapon)
|
|
IF DECOR_EXIST_ON(itemKillCorpse, "hunt_chal_weapon")
|
|
TEXT_LABEL retVal = "HTXT_WCHAL"
|
|
retVal += DECOR_GET_INT(itemKillCorpse, "hunt_chal_weapon")
|
|
RETURN retVal
|
|
ENDIF
|
|
|
|
|
|
INT iScoreInc = GET_SCORE_FOR_KILL_TYPE(eKillType)
|
|
IF iScoreInc < 5 // We have a relatively low score
|
|
AND NOT Player_Hunt_Data.bSentLowPointPerKillText // And we haven't sent a low point text
|
|
AND Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForBronze // We haven't scored a bronze yet
|
|
AND Player_Hunt_Data.iPhotosSent > 4 // We have sent at least 5 photos
|
|
AND (Player_Hunt_Data.iScore / Player_Hunt_Data.iPhotosSent) < 4.0 // And our score per photo is low
|
|
Player_Hunt_Data.bSentLowPointPerKillText = TRUE
|
|
RETURN GET_HUNTING_TEXT_VARIATION("LOWPPK", 5)
|
|
ENDIF
|
|
|
|
IF NOT Player_Hunt_Data.bSentNearBronzeText
|
|
AND Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForBronze
|
|
IF Player_Hunt_Data.iScore + iScoreInc < Player_Hunt_Data.iScoreForBronze
|
|
AND Player_Hunt_Data.iScore + iScoreInc + 5 > Player_Hunt_Data.iScoreForBronze
|
|
Player_Hunt_Data.bSentNearBronzeText = TRUE
|
|
RETURN GET_HUNTING_TEXT_VARIATION("NBRONZE", 3)
|
|
ENDIF
|
|
ELIF NOT Player_Hunt_Data.bSentNearSilverText
|
|
AND Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForSilver
|
|
IF Player_Hunt_Data.iScore + iScoreInc < Player_Hunt_Data.iScoreForSilver
|
|
AND Player_Hunt_Data.iScore + iScoreInc + 5 > Player_Hunt_Data.iScoreForSilver
|
|
Player_Hunt_Data.bSentNearSilverText = TRUE
|
|
RETURN GET_HUNTING_TEXT_VARIATION("NSILVER", 3)
|
|
ENDIF
|
|
ELIF NOT Player_Hunt_Data.bSentNearGoldText
|
|
AND Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForGold
|
|
IF Player_Hunt_Data.iScore + iScoreInc < Player_Hunt_Data.iScoreForGold
|
|
AND Player_Hunt_Data.iScore + iScoreInc + 5 > Player_Hunt_Data.iScoreForGold
|
|
Player_Hunt_Data.bSentNearGoldText = TRUE
|
|
RETURN GET_HUNTING_TEXT_VARIATION("NGOLD", 3)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForBronze
|
|
IF Player_Hunt_Data.iScore + iScoreInc > Player_Hunt_Data.iScoreForBronze
|
|
RETURN GET_HUNTING_TEXT_VARIATION("BRONZE", 3)
|
|
ENDIF
|
|
ELIF Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForSilver
|
|
IF Player_Hunt_Data.iScore + iScoreInc > Player_Hunt_Data.iScoreForSilver
|
|
RETURN GET_HUNTING_TEXT_VARIATION("SILVER", 3)
|
|
ENDIF
|
|
ELIF Player_Hunt_Data.iScore < Player_Hunt_Data.iScoreForGold
|
|
IF Player_Hunt_Data.iScore + iScoreInc > Player_Hunt_Data.iScoreForGold
|
|
RETURN GET_HUNTING_TEXT_VARIATION("GOLD", 3)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Doe kills take priority over weapon kills.
|
|
IF (eKillType = KILL_DOE_KILL)
|
|
RETURN GET_TEXT_MESSAGE_FOR_KILL_TYPE(eKillType)
|
|
ENDIF
|
|
|
|
SWITCH eKillWeapon
|
|
CASE WEAPONTYPE_PISTOL
|
|
CASE WEAPONTYPE_COMBATPISTOL
|
|
CASE WEAPONTYPE_APPISTOL
|
|
CASE WEAPONTYPE_DLC_SNSPISTOL
|
|
IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_PISTOL
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_PISTOL
|
|
RETURN GET_HUNTING_TEXT_VARIATION("PISTOL", 3)
|
|
ENDIF
|
|
BREAK
|
|
|
|
// Sub machine guns
|
|
CASE WEAPONTYPE_MICROSMG
|
|
CASE WEAPONTYPE_SMG
|
|
IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_SMG
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_SMG
|
|
RETURN GET_HUNTING_TEXT_VARIATION("SMG", 3)
|
|
ENDIF
|
|
BREAK
|
|
|
|
// Assault rifles
|
|
CASE WEAPONTYPE_ASSAULTRIFLE
|
|
CASE WEAPONTYPE_CARBINERIFLE
|
|
CASE WEAPONTYPE_DLC_SPECIALCARBINE
|
|
CASE WEAPONTYPE_ADVANCEDRIFLE
|
|
// IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_RIFLE
|
|
// Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_RIFLE
|
|
// RETURN GET_HUNTING_TEXT_VARIATION("RIFLE", 3)
|
|
// ENDIF
|
|
// BREAK
|
|
//
|
|
// // Light machine guns
|
|
CASE WEAPONTYPE_MG
|
|
CASE WEAPONTYPE_COMBATMG
|
|
CASE WEAPONTYPE_MINIGUN
|
|
IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_MG
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_MG
|
|
RETURN GET_HUNTING_TEXT_VARIATION("MG", 3)
|
|
ENDIF
|
|
BREAK
|
|
|
|
// Shotguns
|
|
CASE WEAPONTYPE_PUMPSHOTGUN
|
|
CASE WEAPONTYPE_SAWNOFFSHOTGUN
|
|
CASE WEAPONTYPE_ASSAULTSHOTGUN
|
|
IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_SHOTGUN
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_SHOTGUN
|
|
RETURN GET_HUNTING_TEXT_VARIATION("SHOTGUN", 3)
|
|
ENDIF
|
|
BREAK
|
|
|
|
// Heavy weapons
|
|
CASE WEAPONTYPE_GRENADELAUNCHER
|
|
CASE WEAPONTYPE_RPG
|
|
CASE WEAPONTYPE_GRENADE
|
|
CASE WEAPONTYPE_STICKYBOMB
|
|
CASE WEAPONTYPE_MOLOTOV
|
|
IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_HEAVY
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_HEAVY
|
|
RETURN GET_HUNTING_TEXT_VARIATION("EXPL", 3)
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
// Melee Weapons
|
|
CASE WEAPONTYPE_UNARMED
|
|
CASE WEAPONTYPE_BALL
|
|
CASE WEAPONTYPE_KNIFE
|
|
CASE WEAPONTYPE_NIGHTSTICK
|
|
CASE WEAPONTYPE_HAMMER
|
|
CASE WEAPONTYPE_BAT
|
|
CASE WEAPONTYPE_CROWBAR
|
|
CASE WEAPONTYPE_GOLFCLUB
|
|
CASE WEAPONTYPE_DLC_BOTTLE
|
|
IF Player_Hunt_Data.lastWeaponUsed != WEAPONGROUP_MELEE
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_MELEE
|
|
RETURN GET_HUNTING_TEXT_VARIATION("MELEE", 3)
|
|
ENDIF
|
|
BREAK
|
|
DEFAULT
|
|
Player_Hunt_Data.lastWeaponUsed = WEAPONGROUP_SNIPER
|
|
BREAK
|
|
ENDSWITCH
|
|
RETURN GET_TEXT_MESSAGE_FOR_KILL_TYPE(eKillType)
|
|
ENDFUNC
|
|
|
|
FUNC TEXT_LABEL GET_TEXT_MESSAGE_FOR_WRONG_CONTACT(enumCharacterList charWrongText)
|
|
TEXT_LABEL txtTemp
|
|
SWITCH charWrongText
|
|
CASE CHAR_MICHAEL
|
|
IF NOT IS_PLAYER_PED_AVAILABLE(CHAR_MICHAEL)
|
|
txtTemp = ""
|
|
CPRINTLN(DEBUG_HUNTING, "GET_TEXT_MESSAGE_FOR_WRONG_CONTACT Michael is unplayable, giving no response.")
|
|
RETURN txtTemp
|
|
ENDIF
|
|
CPRINTLN(DEBUG_HUNTING, "GET_TEXT_MESSAGE_FOR_WRONG_CONTACT Michael is playable, giving a response.")
|
|
RETURN GET_HUNTING_TEXT_VARIATION("MICHAEL", 3)
|
|
CASE CHAR_FRANKLIN RETURN GET_HUNTING_TEXT_VARIATION("FRANKLIN", 3)
|
|
CASE CHAR_RON RETURN GET_HUNTING_TEXT_VARIATION("RON", 0)
|
|
CASE CHAR_WADE RETURN GET_HUNTING_TEXT_VARIATION("WADE", 0)
|
|
CASE CHAR_OSCAR RETURN GET_HUNTING_TEXT_VARIATION("OSCAR", 0)
|
|
CASE CHAR_DEVIN
|
|
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_FINALE_C2)
|
|
RETURN GET_HUNTING_TEXT_VARIATION("DEVIN", 0)
|
|
ELSE
|
|
txtTemp = ""
|
|
RETURN txtTemp
|
|
ENDIF
|
|
BREAK
|
|
CASE CHAR_CHENG
|
|
CASE CHAR_CHENGSR
|
|
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_FINALE_C2)
|
|
RETURN GET_HUNTING_TEXT_VARIATION("CHENG", 0)
|
|
ELSE
|
|
txtTemp = ""
|
|
RETURN txtTemp
|
|
ENDIF
|
|
BREAK
|
|
CASE CHAR_JIMMY RETURN GET_HUNTING_TEXT_VARIATION("JIMMY", 0)
|
|
CASE CHAR_DAVE RETURN GET_HUNTING_TEXT_VARIATION("DAVE", 0)
|
|
CASE CHAR_LESTER RETURN GET_HUNTING_TEXT_VARIATION("LESTER", 0)
|
|
CASE CHAR_LAMAR RETURN GET_HUNTING_TEXT_VARIATION("LAMAR", 0)
|
|
CASE CHAR_PATRICIA RETURN GET_HUNTING_TEXT_VARIATION("PATRICIA", 0)
|
|
CASE CHAR_MAUDE RETURN GET_HUNTING_TEXT_VARIATION("MAUDE", 0)
|
|
CASE CHAR_CASTRO RETURN GET_HUNTING_TEXT_VARIATION("CASTRO", 0)
|
|
CASE CHAR_GAYMILITARY RETURN GET_HUNTING_TEXT_VARIATION("GAYMILIT", 0)
|
|
CASE CHAR_HITCHER_GIRL RETURN GET_HUNTING_TEXT_VARIATION("HITCHGRL", 0)
|
|
CASE CHAR_BARRY RETURN GET_HUNTING_TEXT_VARIATION("BARRY", 0)
|
|
CASE CHAR_JOE RETURN GET_HUNTING_TEXT_VARIATION("JOE", 0)
|
|
CASE CHAR_JOSEF RETURN GET_HUNTING_TEXT_VARIATION("JOSEF", 0)
|
|
CASE CHAR_JOSH RETURN GET_HUNTING_TEXT_VARIATION("JOSH", 0)
|
|
CASE CHAR_NIGEL RETURN GET_HUNTING_TEXT_VARIATION("NIGEL", 0)
|
|
|
|
CASE CHAR_ONEIL
|
|
// Between Chinese 2 and Exile 2, the palyer has killed ONeil's family, and then ONeil.
|
|
// He probably should respond during this time.
|
|
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_CHINESE_2)
|
|
txtTemp = ""
|
|
RETURN txtTemp
|
|
ENDIF
|
|
RETURN GET_HUNTING_TEXT_VARIATION("ONEIL", 0)
|
|
BREAK
|
|
ENDSWITCH
|
|
RETURN GET_HUNTING_TEXT_VARIATION("RANDOM_", 3)
|
|
ENDFUNC
|
|
|
|
FUNC STRING GET_TEXT_MESSAGE_FOR_PHOTO_RANK(HUNTING_CHALLENGE_RANK hrRank)
|
|
SWITCH hrRank
|
|
CASE HCR_RANK_1 RETURN "HTXT_PCHAL1"
|
|
CASE HCR_RANK_2 RETURN "HTXT_PCHAL2"
|
|
CASE HCR_RANK_3 RETURN "HTXT_PCHAL3"
|
|
CASE HCR_RANK_4 RETURN "HTXT_PCHAL4"
|
|
CASE HCR_RANK_5 RETURN "HTXT_PCHAL5"
|
|
ENDSWITCH
|
|
RETURN "HTXT_PHOTO_1"
|
|
ENDFUNC
|
|
|
|
FUNC INT DO_CORPSE_PAYMENT(ENTITY_INDEX entCorpse)
|
|
IF NOT IS_ENTITY_DEAD(entCorpse) // Don't give scores for live animals - they are just here for photo challenge
|
|
RETURN 0
|
|
ENDIF
|
|
|
|
IF NOT DECOR_EXIST_ON(entCorpse, "hunt_score")
|
|
RETURN 0
|
|
ENDIF
|
|
|
|
KILL_TYPE eKillType = INT_TO_ENUM(KILL_TYPE, DECOR_GET_INT(entCorpse, "hunt_score"))
|
|
INT iMoney = GET_MONEY_FOR_KILL_TYPE(eKillType)
|
|
FLOAT fMoneyMultiplierForWeapon
|
|
|
|
IF DECOR_EXIST_ON(entCorpse, "hunt_weapon")
|
|
fMoneyMultiplierForWeapon = GET_MONEY_MULTIPLIER_FOR_WEAPONGROUP(GET_WEAPONTYPE_GROUP(INT_TO_ENUM(WEAPON_TYPE, DECOR_GET_INT(entCorpse, "hunt_weapon"))))
|
|
ELSE
|
|
fMoneyMultiplierForWeapon = GET_MONEY_MULTIPLIER_FOR_WEAPONGROUP(WEAPONGROUP_INVALID)
|
|
ENDIF
|
|
|
|
iMoney = ROUND(TO_FLOAT(iMoney) * fMoneyMultiplierForWeapon)
|
|
Player_Hunt_Data.iMoney += iMoney
|
|
CPRINTLN(DEBUG_MISSION, "Payment - ", GET_DISPLAY_NAME_FOR_KILL_TYPE(entCorpse, eKillType),": $", iMoney)
|
|
RETURN iMoney
|
|
ENDFUNC
|
|
|
|
PROC DO_CORPSE_SCORING(ENTITY_INDEX entCorpse)
|
|
IF NOT IS_ENTITY_DEAD(entCorpse) // Don't give scores for live animals - they are just here for photo challenge
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF NOT DECOR_EXIST_ON(entCorpse, "hunt_score")
|
|
EXIT
|
|
ENDIF
|
|
|
|
KILL_TYPE eKillType = INT_TO_ENUM(KILL_TYPE, DECOR_GET_INT(entCorpse, "hunt_score"))
|
|
INT iScore = GET_SCORE_FOR_KILL_TYPE(eKillType)
|
|
|
|
|
|
Player_Hunt_Data.iScore += iScore
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Scoring - ", GET_DISPLAY_NAME_FOR_KILL_TYPE(entCorpse, eKillType),": ", iScore, " Points")
|
|
SCORE_NOTIFICATION( GET_NOTIFICATION_FOR_KILL_TYPE(eKillType), iScore)
|
|
ENDPROC
|
|
|
|
PROC DO_CHALLENGE_RANK_SCORING(HUNTING_CHALLENGE_RANK hrRank)
|
|
INT iScore
|
|
SWITCH hrRank
|
|
CASE HCR_RANK_1 iScore = 5 BREAK
|
|
CASE HCR_RANK_2 iScore = 10 BREAK
|
|
CASE HCR_RANK_3 iScore = 15 BREAK
|
|
CASE HCR_RANK_4 iScore = 20 BREAK
|
|
CASE HCR_RANK_5 iScore = 25 BREAK
|
|
ENDSWITCH
|
|
|
|
IF iScore > 0
|
|
Player_Hunt_Data.iScore += iScore
|
|
|
|
SCORE_NOTIFICATION( "HN_RANK", iScore )
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player has just killed an elk.
|
|
/// Increments the kill counter and records where the elk was shot.
|
|
/// PARAMS:
|
|
/// i - the individual elk to check
|
|
PROC HAS_PLAYER_KILLED_ELK(INT i)
|
|
IF DOES_ENTITY_EXIST(mElk[i].mPed)
|
|
|
|
// Blah debug kill cheat...
|
|
// IF IS_CONTROL_JUST_RELEASED(PLAYER_CONTROL, INPUT_FRONTEND_RB)
|
|
// Player_Hunt_Data.iScore++
|
|
// ENDIF
|
|
|
|
IF NOT IS_ELK_OK(i)
|
|
bSuppressNearMissMessage = TRUE
|
|
WEAPON_TYPE killWeapon
|
|
|
|
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AHT_MISS")
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(mElk[i].mPed, PLAYER_PED_ID())
|
|
CPRINTLN(DEBUG_MISSION, "Elk just harmed by player!")
|
|
|
|
IF HAS_PED_BEEN_DAMAGED_BY_WEAPON(mElk[i].mPed, WEAPONTYPE_RUNOVERBYVEHICLE)
|
|
CPRINTLN(DEBUG_MISSION, "Player used a vehicle...")
|
|
ADD_CORPSE_WITH_LOCATION(mElk[i].mPed, KILL_ROAD_KILL, WEAPONTYPE_RUNOVERBYVEHICLE)
|
|
|
|
IF NOT IS_ELK_A_DOE(mElk[i].mPed)
|
|
Player_Hunt_Data.iKillCount += 1
|
|
|
|
|
|
MARK_ELK_KILL_TIME()
|
|
ENDIF
|
|
IF IS_ENTITY_ALIVE(mElk[i].mPed)
|
|
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(mElk[i].mPed)
|
|
ENDIF
|
|
EXIT
|
|
ENDIF
|
|
|
|
CHECK_WEAPONS_MASTER_CHALLENGE_FOR_ANIMAL(Player_Hunt_Data, mElk[i].mPed)
|
|
|
|
// See how it was killed, then clear that.
|
|
CHECK_TARGET_DAMAGED_BY_RIFLE(mElk[i].mPed)
|
|
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(mElk[i].mPed)
|
|
|
|
TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
|
|
IF mElk[i].bIsSpooked
|
|
CPRINTLN(DEBUG_MISSION, "Killed elk had already been spooked.")
|
|
|
|
// In ambient mode, killing doe doesn't count.
|
|
IF bIsAmbient
|
|
IF NOT IS_ELK_A_DOE(mElk[i].mPed)
|
|
Player_Hunt_Data.iKillCount += 1
|
|
IF GET_GAME_TIMER() > iWhistleCallTime + 30000
|
|
Player_Hunt_Data.iKillsSinceElkCall += 1
|
|
ENDIF
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
|
|
IF NOT GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), killWeapon)
|
|
killWeapon = WEAPONTYPE_INVALID
|
|
ENDIF
|
|
|
|
IF Player_Hunt_Data.iScore < 0
|
|
Player_Hunt_Data.iScore = 0
|
|
ENDIF
|
|
MARK_ELK_KILL_TIME()
|
|
ENDIF
|
|
|
|
IF IS_ELK_A_DOE(mElk[i].mPed)
|
|
ADD_CORPSE_WITH_LOCATION(mElk[i].mPed, KILL_DOE_KILL, killWeapon)
|
|
ELSE
|
|
ADD_CORPSE_WITH_LOCATION(mElk[i].mPed, KILL_SPOOKED_SHOT, killWeapon)
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION, "Elk was killed cleanly.")
|
|
|
|
IF NOT bGotNearMissTime
|
|
iMissMessageDelay = GET_GAME_TIMER() + MISS_MESSAGE_DELAY_TIME
|
|
bSuppressNearMissMessage = TRUE
|
|
bGotNearMissTime = TRUE
|
|
ENDIF
|
|
|
|
// In ambient mode, killing a doe doesn't count.
|
|
IF bIsAmbient //AND NOT IS_ELK_A_DOE(mElk[i].mPed)
|
|
IF NOT IS_ELK_A_DOE(mElk[i].mPed)
|
|
IF bIsAmbient
|
|
CPRINTLN(DEBUG_MISSION, "Recording hit location in slot: ", Player_Hunt_Data.iKillCount)
|
|
RECORD_LAST_HIT_LOCATION(i)
|
|
ENDIF
|
|
|
|
// Increment all counters.
|
|
Player_Hunt_Data.iKillCount += 1
|
|
Player_Hunt_Data.iKillsSinceSpooked += 1
|
|
|
|
IF GET_GAME_TIMER() > iWhistleCallTime + 30000
|
|
Player_Hunt_Data.iKillsSinceElkCall += 1
|
|
ENDIF
|
|
MARK_ELK_KILL_TIME()
|
|
ENDIF
|
|
Player_Hunt_Data.iChallengeDisplayTime = GET_GAME_TIMER() + CHALLENGE_DISPLAY_DELAY
|
|
|
|
ADD_CLEAN_KILL_CORPSE(i)
|
|
ENDIF
|
|
|
|
IF Player_Hunt_Data.iScore > 0
|
|
#IF IS_DEBUG_BUILD
|
|
PRINTLN("KILLCOUNT/SCORE = ", Player_Hunt_Data.iScore)
|
|
#ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
|
|
|
|
INT iTooFarTimer
|
|
/// PURPOSE:
|
|
///
|
|
/// RETURNS:
|
|
///
|
|
FUNC BOOL IS_ANY_VISIBLE_ELK_IN_RANGE()
|
|
|
|
//CPRINTLN(DEBUG_MISSION,"CHECKING IF ANY ELK IS IN RANGE OF THE PLAYER")
|
|
INT i, iNumInRange = 0
|
|
REPEAT MAX_ELKS i
|
|
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
IF IS_ELK_OK(i)
|
|
IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), mElk[i].mPed, CLOSE_KILL_RANGE)
|
|
IF IS_ENTITY_ON_SCREEN(mElk[i].mPed)
|
|
AND NOT WOULD_ENTITY_BE_OCCLUDED(mElk[i].mModel, GET_ENTITY_COORDS(mElk[i].mPed, FALSE))
|
|
AND NOT mElk[i].bIsSpooked
|
|
iNumInRange++
|
|
ENDIF
|
|
ELSE
|
|
//CPRINTLN(DEBUG_MISSION,"THIS ELK IS TOO FAR: ", i)
|
|
IF IS_PLAYER_FREE_AIMING_AT_ENTITY(PLAYER_ID(), mElk[i].mPed) AND NOT mElk[i].bIsSpooked
|
|
//CPRINTLN(DEBUG_MISSION,"TEH PLAYER IS AIMING AT ELK: ", i)
|
|
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AHT_TOFAR")
|
|
iTooFarTimer = GET_GAME_TIMER() + 3000
|
|
//PRINT_HELP("AHT_TOFAR")
|
|
ENDIF
|
|
ELSE
|
|
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AHT_TOFAR")
|
|
IF GET_GAME_TIMER() > iTooFarTimer
|
|
OR mElk[i].bIsSpooked
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
IF iNumInRange > 0
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player is within CLOSE_KILL_RANGE of the Elk he is aiming at and prints help
|
|
/// to the screen to let the player know he can make a close kill.
|
|
PROC CHECK_PLAYER_IN_RANGE()
|
|
|
|
IF IS_ANY_VISIBLE_ELK_IN_RANGE()
|
|
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AHT_RANGE")
|
|
PRINT_HELP("AHT_RANGE")
|
|
ENDIF
|
|
ELSE
|
|
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AHT_RANGE")
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if any elk is spooked
|
|
/// RETURNS:
|
|
/// TRUE if the player has spooked an elk
|
|
FUNC BOOL IS_ANY_ELK_SPOOKED()
|
|
|
|
INT i
|
|
REPEAT MAX_ELKS i
|
|
IF IS_ELK_OK(i)
|
|
IF mElk[i].bIsSpooked //AND NOT mElk[i].bGotNearMissTime
|
|
//CPRINTLN(DEBUG_MISSION, "IS_ANY_ELK_SPOOKED return true - ", i)
|
|
RETURN TRUE
|
|
ELSE
|
|
//CPRINTLN(DEBUG_MISSION, "IS_ANY_ELK_SPOOKED returns false - ", i)
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
|
|
PROC SPAWN_HERD_MEMBERS(INT iHerdLeaderIndex)
|
|
// Track how many are in the herd, as there's a max. We start at 1, because being here means there's a leader.
|
|
INT iSpawnedInHerd = 1
|
|
INT i = HERD_MEMBER_INDEX_START
|
|
WHILE (i < MAX_ELKS) AND (iSpawnedInHerd < MAX_ELK_PER_HERD)
|
|
IF NOT IS_ELK_OK(i)
|
|
IF GET_RANDOM_INT_IN_RANGE(0, 100) < PERCENTAGE_HERD_MEMBER_CHANCE
|
|
SPAWN_ELK_HERD_MEMBER(i, iHerdLeaderIndex)
|
|
iSpawnedInHerd += 1
|
|
mElk[iHerdLeaderIndex].iNumFollowers += 1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
++i
|
|
ENDWHILE
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Resets the timer on all elk calls.
|
|
PROC RESET_ALL_ELK_CALLS()
|
|
INT idx
|
|
REPEAT MAX_ELKS idx
|
|
mElk[idx].iCallTime = GET_GAME_TIMER()
|
|
ENDREPEAT
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
ENDPROC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Handles the elk calling to each other randomly, as well as responding to player.
|
|
/// Only happens if the elk is not spooked.
|
|
PROC MANAGE_ELK_CALLS(INT iElkIdx)
|
|
// Don't call if the elk isn't alive.
|
|
IF NOT IS_ELK_OK(iElkIdx)
|
|
EXIT
|
|
ENDIF
|
|
IF NOT mElk[iElkIdx].bRandomlyCalls
|
|
EXIT
|
|
ENDIF
|
|
IF mElk[iElkIdx].bIsSpooked
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF bPlayerCalling
|
|
AND iCallEndTime + BLEAT_RESPONSE_DELAY + 5000 < GET_GAME_TIMER()
|
|
AND mElk[iElkIdx].iCallTime < GET_GAME_TIMER()
|
|
// Okay, so the player has called... Select a few elk to respond.
|
|
bPlayerCalling = FALSE
|
|
|
|
// Determine if this elk responds.
|
|
//IF GET_RANDOM_INT_IN_RANGE(0, 100) < 90
|
|
mElk[iElkIdx].iCallTime = GET_GAME_TIMER()
|
|
mElk[iElkIdx].bCalling = TRUE
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_BREY_MASTER", mElk[iElkIdx].mPed)
|
|
CPRINTLN(DEBUG_MISSION, "Elk replying to call: ", iElkIdx)
|
|
|
|
iInitiatorIndex = -1
|
|
|
|
// Don't trigger random bleats for a bit
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
//ENDIF
|
|
ENDIF
|
|
|
|
// Okay, make sure that it's not time for a random bleat.
|
|
IF (iBleatInitiateTime != -1) AND iBleatInitiateTime < GET_GAME_TIMER()
|
|
// This guy will be our initiator.
|
|
mElk[iElkIdx].bCalling = TRUE
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_BREY_MASTER", mElk[iElkIdx].mPed)
|
|
CPRINTLN(DEBUG_MISSION, "Elk Brey Initiate!")
|
|
|
|
iBleatResponseTime = GET_GAME_TIMER() + BLEAT_RESPONSE_DELAY
|
|
iInitiatorIndex = iElkIdx
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
|
|
ELIF (iInitiatorIndex != -1) AND (iBleatResponseTime < GET_GAME_TIMER()) AND (iBleatResponseTime != -1)
|
|
IF (iElkIdx != iInitiatorIndex)
|
|
//// 90% chance an elk is going to respond.
|
|
//IF GET_RANDOM_INT_IN_RANGE(0, 100) < 90
|
|
mElk[iElkIdx].iCallTime = GET_GAME_TIMER()
|
|
mElk[iElkIdx].bCalling = TRUE
|
|
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_BREY_MASTER", mElk[iElkIdx].mPed)
|
|
iBleatResponseTime = GET_GAME_TIMER() + BLEAT_RESPONSE_DELAY
|
|
//ENDIF
|
|
ENDIF
|
|
bRandomBleat = TRUE
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Removes any other blip on a spooked animal, and adds aa fleeing blip.
|
|
PROC SETUP_ELK_SPOOKED_BLIP(MY_ELK & thisElk)
|
|
IF DOES_BLIP_EXIST(thisElk.mElkBlip)
|
|
CPRINTLN(DEBUG_MISSION, "Removing previous elk blip before adding spooked blip.")
|
|
REMOVE_BLIP(thisElk.mElkBlip)
|
|
ENDIF
|
|
|
|
IF NOT thisElk.bBlockSpookedBlip
|
|
CPRINTLN(DEBUG_MISSION, "Adding an elk spooked blip!")
|
|
ADD_SAFE_BLIP_TO_PED(thisElk.mElkBlip, thisElk.mPed, TRUE, BLIP_SIZE_PED)
|
|
SET_BLIP_ALPHA(thisElk.mElkBlip, 128)
|
|
SET_BLIP_SHOW_CONE(thisElk.mElkBlip, TRUE)
|
|
ENDIF
|
|
|
|
thisElk.bIsSpooked = TRUE
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Lets you disable a spooked blip on an elk.
|
|
PROC SET_ELK_SPOOKED_BLIP_ENABLED(MY_ELK & thisElk, BOOL bSpookedBlipEnabled = TRUE)
|
|
thisElk.bBlockSpookedBlip = !bSpookedBlipEnabled
|
|
ENDPROC
|
|
|
|
// ====================
|
|
// ELK STATES
|
|
// ====================
|
|
|
|
|
|
/// PURPOSE:
|
|
/// The state machine for the elk
|
|
/// PARAMS:
|
|
/// i - the index of the elk to be processed.
|
|
PROC CHECK_ELK_STATES(INT i)
|
|
IF mElk[i].bIsSpooked
|
|
//CPRINTLN(DEBUG_MISSION, "Checking at top of elk state machine - THIS ELK IS SPOOKED ", i)
|
|
IF DOES_ENTITY_EXIST(mElk[i].mPed) AND IS_ENTITY_DEAD(mElk[i].mPed)
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(mElk[i].mPed, PLAYER_PED_ID())
|
|
bUncleanKill = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CHECK_ELK_SPOOKED(i)
|
|
MANAGE_ELK_CALLS(i)
|
|
|
|
// Don't want to tweak the blips if the elk is spooked.
|
|
MANAGE_ELK_BLIP(mElk[i], i)
|
|
|
|
// Cleanup far away elk.
|
|
IF bIsAmbient
|
|
FLOAT fDistance = 9999.9
|
|
IF DOES_ENTITY_EXIST(mElk[i].mPed)
|
|
IF NOT IS_PED_INJURED(mElk[i].mPed)
|
|
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
|
|
VECTOR vElkPos = GET_ENTITY_COORDS(mElk[i].mPed)
|
|
fDistance = GET_DISTANCE_BETWEEN_COORDS(vHuntingPlayerCoords, vElkPos)
|
|
|
|
IF fDistance > ELK_CLEANUP_DISTANCE
|
|
IF NOT IS_SPHERE_VISIBLE(vElkPos, 2.0)
|
|
OR IS_SCREEN_FADED_OUT()
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Herd members just wait for the leader to do something new.
|
|
IF (mElk[i].bIsHerdMember)
|
|
mElk[i].elkState = mElk[mElk[i].iLeaderIdx].elkState
|
|
EXIT
|
|
ENDIF
|
|
|
|
SWITCH mElk[i].elkState
|
|
// HOLDING AREA
|
|
CASE ES_NULL
|
|
// DO NOTHING
|
|
BREAK
|
|
|
|
|
|
CASE ES_CHECK_CAN_SPAWN
|
|
IF bIsAmbient
|
|
//CPRINTLN(DEBUG_MISSION,"ES_CHECK_CAN_SPAWN - Elks In Play is ", iElksInPlay)
|
|
IF iElksInPlay < MAX_ELKS AND NOT bIsPlayerOutsideHuntArea
|
|
// First elk can spawn without a delay
|
|
IF NOT mElk[i].bDelayBeforeRespawn
|
|
CPRINTLN(DEBUG_MISSION,"ES_CHECK_CAN_SPAWN - SPAWNING IN")
|
|
mElk[i].elkState = ES_SPAWN_IN
|
|
// need to wait for any delayed spooked messages/flags to be sorted out before repsawn
|
|
ELIF GET_GAME_TIMER() > mElk[i].iSpawnDelayTime
|
|
//CPRINTLN(DEBUG_MISSION,"ES_CHECK_CAN_SPAWN AFTER DELAY - SPAWNING IN")
|
|
mElk[i].elkState = ES_SPAWN_IN
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
// CREATES AN ELK IN A VACANT GRAZE AREA. SETS A RANDOM HEADING. BLIPS THE ELK WITH A TRANSPARENT BLIP.
|
|
CASE ES_SPAWN_IN
|
|
IF SPAWN_ELK(i, ES_PAUSE_THEN_GRAZE)
|
|
//CPRINTLN(DEBUG_MISSION,"ES_SPAWN_IN - Elks In Play is now: ", iElksInPlay)
|
|
|
|
// Only male elk can be herd leaders.
|
|
IF bIsAmbient AND NOT IS_ELK_A_DOE(mElk[i].mPed)
|
|
// If no herd is active, try to spawn a herd around the elk, and set it to static behaviour
|
|
IF NOT IS_ANY_ELK_A_HERD_MEMBER()
|
|
IF GET_RANDOM_INT_IN_RANGE(0, 100) < PERCENTAGE_HERD_CHANCE
|
|
mElk[i].elkState = ES_START_GRAZE
|
|
SPAWN_HERD_MEMBERS(i)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_START_GRAZE
|
|
// This elk is to graze. Start the anim and figure out how long to graze for.
|
|
IF NOT mElk[i].bIsSpooked
|
|
INT iRand
|
|
iRand = GET_RANDOM_INT_IN_RANGE() % 3
|
|
SEQUENCE_INDEX Seq
|
|
OPEN_SEQUENCE_TASK(Seq)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@enter", "enter")
|
|
IF (iRand = 0)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_a", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING)
|
|
ELIF (iRand = 1)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_b", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING)
|
|
ELSE
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_c", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING)
|
|
ENDIF
|
|
CLOSE_SEQUENCE_TASK(Seq)
|
|
TASK_PERFORM_SEQUENCE(mElk[i].mPed, Seq)
|
|
CLEAR_SEQUENCE_TASK(Seq)
|
|
|
|
mElk[i].iWaitTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(MIN_ELK_GRAZE_TIME, MAX_ELK_GRAZE_TIME)
|
|
mElk[i].elkState = ES_GRAZE
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION,"Elk spooked from Graze state")
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_GRAZE
|
|
// Here, the elk is grazing.
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
VECTOR vElkPos
|
|
vElkPos = GET_ENTITY_COORDS(mElk[i].mPed)
|
|
IF GET_GAME_TIMER() > mElk[i].iWaitTime
|
|
AND WOULD_POINT_BE_IN_FRONT_OF_PLAYER(vElkPos)
|
|
AND VDIST2(vElkPos, GET_ENTITY_COORDS(PLAYER_PED_ID())) < 10000.0
|
|
// Time to move on.
|
|
SEQUENCE_INDEX Seq
|
|
OPEN_SEQUENCE_TASK(Seq)
|
|
IF (GET_SCRIPT_TASK_STATUS(mElk[i].mPed, SCRIPT_TASK_PERFORM_SEQUENCE) = PERFORMING_TASK)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@exit", "exit", SLOW_BLEND_IN)
|
|
ENDIF
|
|
TASK_LOOK_AT_ENTITY(NULL, PLAYER_PED_ID(), 4200)
|
|
CLOSE_SEQUENCE_TASK(Seq)
|
|
TASK_PERFORM_SEQUENCE(mElk[i].mPed, Seq)
|
|
CLEAR_SEQUENCE_TASK(Seq)
|
|
|
|
// Pause, then move
|
|
mElk[i].iWaitTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(MIN_ELK_WAIT_TIME, MAX_ELK_WAIT_TIME)
|
|
mElk[i].elkState = ES_PAUSE_THEN_PICK_NEW_DESTINATION
|
|
ENDIF
|
|
ELSE
|
|
// Elk is spooked, clean.
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_PAUSE_THEN_PICK_NEW_DESTINATION
|
|
// Okay, we're waiting for a set time, then we'll go to a new destination.
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
IF GET_GAME_TIMER() > mElk[i].iWaitTime
|
|
// Pick a new destination and go there.
|
|
mElk[i].elkState = ES_CHOOSE_NEXT_DESTINATION
|
|
ENDIF
|
|
ELSE
|
|
// Elk is spooked, run.
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_CHOOSE_NEXT_DESTINATION
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
// Get a random node, and go to it.
|
|
iRandGraze = GET_RANDOM_INT_IN_RANGE(0, MAX_GRAZE_AREAS)
|
|
|
|
IF IS_NODE_OK_FOR_THIS_ELK(i, iRandGraze)
|
|
mElk[i].iDestNode = iRandGraze
|
|
ELSE
|
|
mElk[i].iDestNode = FIND_BEST_CLOSEST_NODE(i)
|
|
ENDIF
|
|
|
|
elkSpawn[mElk[i].iCurNode].bIsBooked = FALSE
|
|
IF bIsAmbient
|
|
elkSpawn[mElk[i].iDestNode].bIsBooked = TRUE
|
|
ENDIF
|
|
|
|
TASK_FOLLOW_NAV_MESH_TO_COORD(mElk[i].mPed, elkSpawn[mElk[i].iDestNode].vCoord, PEDMOVEBLENDRATIO_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT, ENAV_DEFAULT)
|
|
mElk[i].iPrevNode = mElk[i].iCurNode
|
|
|
|
// Go to that destination.
|
|
mElk[i].elkState = ES_TRAVEL_TO_NEXT_DESTINATION
|
|
ELSE
|
|
// Spooked, run.
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_TRAVEL_TO_NEXT_DESTINATION
|
|
//CPRINTLN(DEBUG_MISSION,"ES_GO_TO_NEXT_DESTINATION")
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
IF IS_ENTITY_AT_COORD(mElk[i].mPed, elkSpawn[mElk[i].iDestNode].vCoord, <<3.0, 3.0, 3.0>>, FALSE, FALSE, TM_ANY)
|
|
mElk[i].iCurNode = mElk[i].iDestNode
|
|
CLEAR_PED_TASKS(mElk[i].mPed)
|
|
|
|
mElk[i].iWaitTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(MIN_ELK_WAIT_TIME, MAX_ELK_WAIT_TIME)
|
|
mElk[i].elkState = ES_PAUSE_THEN_GRAZE
|
|
ENDIF
|
|
ELSE
|
|
//CPRINTLN(DEBUG_MISSION,"ES - SPOOKED - RUN OFF")
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE ES_TRAVEL_THEN_ENTER_GRAZE_AND_WAIT_TO_DIE
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
IF IS_ENTITY_AT_COORD(mElk[i].mPed, elkSpawn[mElk[i].iDestNode].vCoord, <<3.0, 3.0, 3.0>>, FALSE, FALSE, TM_ANY)
|
|
mElk[i].iCurNode = mElk[i].iDestNode
|
|
CLEAR_PED_TASKS(mElk[i].mPed)
|
|
|
|
mElk[i].iWaitTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(MIN_ELK_WAIT_TIME, MAX_ELK_WAIT_TIME)
|
|
mElk[i].elkState = ES_ENTER_GRAZE_AND_WAIT_TO_DIE
|
|
ENDIF
|
|
ELSE
|
|
//CPRINTLN(DEBUG_MISSION,"ES - SPOOKED - RUN OFF")
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_PAUSE_THEN_GRAZE
|
|
// Okay, we're waiting for a set time, then we'll go to a new destination.
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
IF GET_GAME_TIMER() > mElk[i].iWaitTime
|
|
// Need to graze.
|
|
mElk[i].elkState = ES_START_GRAZE
|
|
ENDIF
|
|
ELSE
|
|
// Elk is spooked, run.
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_RUN_OFF
|
|
//CPRINTLN(DEBUG_MISSION,"[ES] ES_RUN_OFF")
|
|
IF bIsPlayerOutsideHuntArea
|
|
CPRINTLN(DEBUG_MISSION, "Elk running away and player isn't in hunting area. Kill blip.")
|
|
SAFE_REMOVE_BLIP(mElk[i].mElkBlip)
|
|
ENDIF
|
|
|
|
IF IS_ELK_OK(i)
|
|
CPRINTLN(DEBUG_MISSION, "ES_RUN_OFF -> Setting up run off.")
|
|
SETUP_ELK_SPOOKED_BLIP(mElk[i])
|
|
|
|
CLEAR_PED_TASKS(mElk[i].mPed)
|
|
TASK_SMART_FLEE_PED(mElk[i].mPed, PLAYER_PED_ID(), 500.0, -1, FALSE)
|
|
SET_PED_KEEP_TASK(mElk[i].mPed, TRUE)
|
|
//CPRINTLN(DEBUG_MISSION,"ES - RUNNING OFF")
|
|
mElk[i].elkState = ES_RUNNING_OFF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
|
|
CASE ES_ENTER_GRAZE_AND_WAIT_TO_DIE
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
|
|
IF GET_SCRIPT_TASK_STATUS(mElk[i].mPed, SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK
|
|
OR GET_SCRIPT_TASK_STATUS(mElk[i].mPed, SCRIPT_TASK_PERFORM_SEQUENCE) != PERFORMING_TASK
|
|
SEQUENCE_INDEX mEnterSeq
|
|
OPEN_SEQUENCE_TASK(mEnterSeq)
|
|
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@enter", "enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@base", "base", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
|
|
IF GET_RANDOM_BOOL()
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_b", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@base", "base")
|
|
ENDIF
|
|
|
|
IF GET_RANDOM_BOOL()
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_a", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
ELSE
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_c", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
ENDIF
|
|
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@base", "base", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@exit", "exit", NORMAL_BLEND_IN, SLOW_BLEND_OUT)
|
|
CLOSE_SEQUENCE_TASK(mEnterSeq)
|
|
TASK_PERFORM_SEQUENCE(mElk[i].mPed, mEnterSeq)
|
|
CLEAR_SEQUENCE_TASK(mEnterSeq)
|
|
|
|
mElk[i].iGrazeTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(10000, 15000)
|
|
mElk[i].elkState = ES_GRAZE_AND_WAIT_TO_DIE
|
|
ENDIF
|
|
ELSE
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed) // Elk is dead
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE ES_GRAZE_AND_WAIT_TO_DIE
|
|
IF IS_ELK_OK(i)
|
|
IF NOT mElk[i].bIsSpooked
|
|
IF GET_SCRIPT_TASK_STATUS(mElk[i].mPed, SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK
|
|
OR GET_SCRIPT_TASK_STATUS(mElk[i].mPed, SCRIPT_TASK_PERFORM_SEQUENCE) <> PERFORMING_TASK
|
|
|
|
IF GET_GAME_TIMER() > mElk[i].iGrazeTime
|
|
SEQUENCE_INDEX mExitSeq
|
|
OPEN_SEQUENCE_TASK(mExitSeq)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@enter", "enter", FAST_BLEND_IN, NORMAL_BLEND_OUT)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@base", "base", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
IF GET_RANDOM_BOOL()
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@base", "base", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@idle_a", "idle_b", NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
|
|
ENDIF
|
|
TASK_PLAY_ANIM(NULL, "creatures@deer@amb@world_deer_grazing@exit", "exit", NORMAL_BLEND_IN, SLOW_BLEND_OUT)
|
|
CLOSE_SEQUENCE_TASK(mExitSeq)
|
|
TASK_PERFORM_SEQUENCE(mElk[i].mPed, mExitSeq)
|
|
CLEAR_SEQUENCE_TASK(mExitSeq)
|
|
|
|
mElk[i].elkState = ES_ENTER_GRAZE_AND_WAIT_TO_DIE
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ELSE
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed) // Elk is dead
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
// CHECKS IF THE ELK IS OFF-SCREEN...
|
|
CASE ES_RUNNING_OFF
|
|
IF IS_ELK_OK(i)
|
|
AND IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
FLOAT fDist
|
|
VECTOR vElkPos
|
|
vElkPos = GET_ENTITY_COORDS(mElk[i].mPed, FALSE)
|
|
fDist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), vElkPos)
|
|
IF (fDist > 70.0) AND NOT IS_SPHERE_VISIBLE(vElkPos, 5.0)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
ELSE
|
|
//TRIGGER_HUNTING_AUDIO("HUNTING_KILL", TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "ELK_PAIN_MASTER", mElk[i].mPed)
|
|
mElk[i].elkState = ES_CLEAN_UP
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE ES_CLEAN_UP
|
|
//CPRINTLN(DEBUG_MISSION,"ES - CLEANING UP")
|
|
CPRINTLN(DEBUG_MISSION, "Cleanup elk. Remove blip.")
|
|
SAFE_REMOVE_BLIP(mElk[i].mElkBlip)
|
|
|
|
// This node is not booked.
|
|
elkSpawn[mElk[i].iCurNode].bIsBooked = FALSE
|
|
elkSpawn[mElk[i].iDestNode].bIsBooked = FALSE
|
|
|
|
// Don't let either the dest node or the cur node respawn for a while.
|
|
elkSpawn[mElk[i].iCurNode].iNextSpawnTime = GET_GAME_TIMER() + ELK_SPAWN_RESPAWN_DELAY
|
|
elkSpawn[mElk[i].iDestNode].iNextSpawnTime = GET_GAME_TIMER() + ELK_SPAWN_RESPAWN_DELAY
|
|
|
|
IF DOES_ENTITY_EXIST(mElk[i].mPed)
|
|
// If a doe, decrement the number in play.
|
|
IF DECOR_EXIST_ON(mElk[i].mPed, "doe_elk")
|
|
iDoeInPlay -= 1
|
|
ENDIF
|
|
|
|
SET_PED_AS_NO_LONGER_NEEDED(mElk[i].mPed)
|
|
ENDIF
|
|
|
|
IF (iElkTesting = i)
|
|
iElkTesting = -1
|
|
elkShapeTest = NULL
|
|
ENDIF
|
|
|
|
iElksInPlay--
|
|
//CPRINTLN(DEBUG_MISSION,"Elk cleaned. Elks in play is now", iElksInPlay)
|
|
mElk[i].iSpawnDelayTime = GET_GAME_TIMER() + SPAWN_DELAY_TIME
|
|
mElk[i].bDelayBeforeRespawn = TRUE
|
|
mElk[i].bIsHerdMember = FALSE
|
|
mElk[i].bIsHerdLeader = FALSE
|
|
SET_ELK_SPOOKED(i, FALSE)
|
|
mElk[i].bBlockSpookedBlip = FALSE
|
|
mElk[i].iLeaderIdx = -1
|
|
mElk[i].iCallResponseTime = 0
|
|
mElk[i].elkState = ES_CHECK_CAN_SPAWN
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Flags all elk as spooked and gets them to run off.
|
|
/// Called when the player leaves the hunt area to prevent him from being able to get kills when he's
|
|
/// being told to return to the hunt area.
|
|
PROC SPOOK_ALL_ELK()
|
|
|
|
INT i
|
|
REPEAT MAX_ELKS i
|
|
IF IS_ELK_OK(i)
|
|
mElk[i].elkState = ES_RUN_OFF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
ENDPROC
|
|
|
|
// Returns true if the player left the hunt area
|
|
// after being warned
|
|
FUNC BOOL DID_PLAYER_LEAVE_AREA()
|
|
|
|
IF NOT IS_PLAYER_IN_IMMEDIATE_HUNT_AREA()
|
|
IF NOT bIsPlayerOutsideHuntArea
|
|
IF NOT bIsAmbient
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
|
|
PRINT_NOW("AHT_RTN", DEFAULT_GOD_TEXT_TIME, 0) // GET BACK TO THE HUNTING AREA
|
|
mCentreBlip = CREATE_COORD_BLIP(mAreaCheck1.vCentre, BLIPPRIORITY_HIGH, FALSE)
|
|
SPOOK_ALL_ELK()
|
|
bAllowCall = FALSE
|
|
bIsPlayerOutsideHuntArea = TRUE
|
|
ELSE
|
|
// Yes, he is outside the area
|
|
CPRINTLN(DEBUG_MISSION,"PLAYER HAS BEEN WARNED - TIMERA IS ", TIMERA())
|
|
IF NOT IS_PLAYER_IN_OUTER_HUNT_AREA()
|
|
SAFE_REMOVE_BLIP(mCentreBlip)
|
|
CPRINTLN(DEBUG_MISSION,"PLAYER LEFT AREA")
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF bIsPlayerOutsideHuntArea
|
|
CPRINTLN(DEBUG_MISSION,"PLAYER IS BACK INSIDE")
|
|
CLEAR_PRINTS()
|
|
|
|
IF DOES_BLIP_EXIST(mCentreBlip)
|
|
REMOVE_BLIP(mCentreBlip)
|
|
ENDIF
|
|
|
|
IF NOT bIsAmbient
|
|
PRINT_HELP("AHT_CALL")
|
|
ENDIF
|
|
|
|
bAllowCall = TRUE
|
|
bIsPlayerOutsideHuntArea = FALSE
|
|
|
|
// Reset all animal and elk calls, that way the player isn't inundated as soon as he enters the area.
|
|
//RESET_ALL_ANIMAL_CALLS()
|
|
RESET_ALL_ELK_CALLS()
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
// ==============
|
|
// WIND FUNCTIONS
|
|
// ==============
|
|
|
|
/// PURPOSE:
|
|
/// Sets the direction of the wind indicator on the HUD.
|
|
/// PARAMS:
|
|
/// huntingUI -
|
|
/// fRotation -
|
|
/// fSpeed -
|
|
PROC SET_WIND_DIRECTION_FOR_HUNTING(SCALEFORM_INDEX huntingUI, FLOAT fRotation = -1.0, FLOAT fSpeed = -1.0)
|
|
BEGIN_SCALEFORM_MOVIE_METHOD(huntingUI, "SET_WIND_DIRECTION")
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(fRotation)
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(fSpeed)
|
|
END_SCALEFORM_MOVIE_METHOD()
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Sets the direction of the compass (relative to player heading) on the compass on the HUD
|
|
/// PARAMS:
|
|
/// huntingUI -
|
|
/// fRotation -
|
|
PROC SET_COMPASS(SCALEFORM_INDEX huntingUI, FLOAT fRotation = -1.0)
|
|
BEGIN_SCALEFORM_MOVIE_METHOD(huntingUI, "SET_COMPASS_DIRECTION")
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(fRotation)
|
|
END_SCALEFORM_MOVIE_METHOD()
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Tints the HUD wind display to the params passed in
|
|
/// PARAMS:
|
|
/// huntingUI - the handle to the UI element
|
|
/// R - Red
|
|
/// B - Blue
|
|
/// G - Green
|
|
PROC SET_WIND_TINT(SCALEFORM_INDEX huntingUI, INT R, INT B, INT G = 0)
|
|
BEGIN_SCALEFORM_MOVIE_METHOD(huntingUI, "TINT_WIND_POINTER")
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) //Arrow
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(R) //Red
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(G) //Green
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(B) //Blue
|
|
END_SCALEFORM_MOVIE_METHOD()
|
|
ENDPROC
|
|
|
|
//CONST_INT iGREENRedVal 74
|
|
//CONST_INT iGREENGreenVal 170
|
|
//CONST_INT iGREENBlueVal 47
|
|
//
|
|
//CONST_INT iREDRedVal 245
|
|
//CONST_INT iREDGreenVal 44
|
|
//CONST_INT iREDBlueVal 16
|
|
|
|
// Start the wind indicator off green
|
|
INT iRedx = -1
|
|
INT iGreenx = 0
|
|
INT iBluex = 0
|
|
|
|
INT iCapR_R = -1
|
|
INT iCapR_G
|
|
INT iCapR_B
|
|
INT iCapG_R
|
|
INT iCapG_G
|
|
INT iCapG_B
|
|
|
|
/// PURPOSE:
|
|
/// Updates the wind scaleform
|
|
/// PARAMS:
|
|
/// bOverride - In Hunt 2 this flag is set to override the actual wind direction with one
|
|
/// set by the last param
|
|
/// i - The direction we want to override the direction of the wind with
|
|
PROC UPDATE_WIND_BLIP(BOOL bOverride = FALSE, FLOAT i = 270.0)
|
|
// On first update, make sure we set our starting vals.
|
|
IF (iRedx = -1)
|
|
INT iDontCare
|
|
GET_HUD_COLOUR(HUD_COLOUR_GREEN, iRedx, iGreenx, iBluex, iDontCare)
|
|
|
|
// Get caps too
|
|
GET_HUD_COLOUR(HUD_COLOUR_GREEN, iCapG_R, iCapG_G, iCapG_B, iDontCare)
|
|
GET_HUD_COLOUR(HUD_COLOUR_RED, iCapR_R, iCapR_G, iCapR_B, iDontCare)
|
|
ENDIF
|
|
|
|
FLOAT tempWind = 0.0
|
|
VECTOR camRot = GET_GAMEPLAY_CAM_ROT()
|
|
|
|
IF NOT bOverride
|
|
IF NOT IS_ENTITY_DEAD (PLAYER_PED_ID())
|
|
vWindDirection = GET_WIND_DIRECTION()
|
|
fWindDirection = GET_HEADING_FROM_VECTOR_2D(vWindDirection.x, vWindDirection.y)
|
|
tempWind = camRot.z - fWindDirection
|
|
ENDIF
|
|
ELSE
|
|
fWindDirection = i
|
|
tempWind = camRot.z - i
|
|
ENDIF
|
|
|
|
WHILE fWindDirection < 0
|
|
fWindDirection+=360.0
|
|
ENDWHILE
|
|
WHILE tempWind < 0
|
|
tempWind += 360.0
|
|
ENDWHILE
|
|
|
|
FLOAT windSpeed = GET_WIND_SPEED()
|
|
|
|
IF PLAYER_CLOSE_TO_BEING_DETECTED()
|
|
IF iRedx < iCapR_R
|
|
iRedx++
|
|
ELIF iRedx > iCapR_R
|
|
iRedx--
|
|
ENDIF
|
|
IF iBluex < iCapR_B
|
|
iBluex++
|
|
ELIF iBluex > iCapR_B
|
|
iBluex--
|
|
ENDIF
|
|
IF iGreenx < iCapR_G
|
|
iGreenx++
|
|
ELIF iGreenx > iCapR_G
|
|
iGreenx--
|
|
ENDIF
|
|
ELSE
|
|
IF iRedx < iCapG_R
|
|
iRedx++
|
|
ELIF iRedx > iCapG_R
|
|
iRedx--
|
|
ENDIF
|
|
IF iBluex < iCapG_B
|
|
iBluex++
|
|
ELIF iBluex > iCapG_B
|
|
iBluex--
|
|
ENDIF
|
|
IF iGreenx < iCapG_G
|
|
iGreenx++
|
|
ELIF iGreenx > iCapG_G
|
|
iGreenx--
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Call drawing funcs.
|
|
DRAW_GENERIC_WIND_METER("AHT_WIND_UPPR", ROUND(windSpeed), tempWind, iRedx, iGreenx, iBluex, HUDORDER_FOURTHBOTTOM)
|
|
ENDPROC
|
|
|
|
|
|
/// =====
|
|
/// AUDIO
|
|
/// =====
|
|
|
|
/// PURPOSE:
|
|
/// Returns the audio values to default when the player stops aiming down the sight.
|
|
PROC RETURN_AUDIO()
|
|
|
|
fConcentration -= 0.05
|
|
|
|
IF NOT IS_ANY_ELK_OK()
|
|
fHeartBeat -= 0.05
|
|
ENDIF
|
|
|
|
IF fConcentration <= 0.0
|
|
//OR fHeartBeat <= 70.0
|
|
fConcentration = 0.0
|
|
//fHeartBeat = 70.0
|
|
IF IS_AUDIO_SCENE_ACTIVE("HUNTING_02_SETTINGS")
|
|
STOP_AUDIO_SCENE("HUNTING_02_SETTINGS")
|
|
STOP_SOUND(iSoundID)
|
|
RELEASE_SOUND_ID(iSoundID)
|
|
iSoundID = -1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF fConcentration >= 1.0
|
|
fConcentration = 1.0
|
|
ENDIF
|
|
|
|
IF fHeartBeat >= 100.0
|
|
fHeartBeat = 100.0
|
|
ENDIF
|
|
|
|
IF fHeartBeat <= 70.0
|
|
fHeartBeat = 70.0
|
|
ENDIF
|
|
|
|
IF IS_AUDIO_SCENE_ACTIVE("HUNTING_02_SETTINGS")
|
|
SET_AUDIO_SCENE_VARIABLE("HUNTING_02_SETTINGS","Concentration",fConcentration)
|
|
SET_AUDIO_SCENE_VARIABLE("HUNTING_02_SETTINGS","Breathing",fConcentration)
|
|
SET_VARIABLE_ON_SOUND(iSoundId, "Concentration", fHeartBeat)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Works out where to start the concentration level from based on the players previous movement.
|
|
/// PARAMS:
|
|
/// fConc -
|
|
/// fHeart -
|
|
PROC WORK_OUT_INITAL_CONCENTRATION(FLOAT &fConc, FLOAT &fHeart)
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
IF IS_PED_RUNNING(PLAYER_PED_ID())
|
|
fConc = 0.2
|
|
fHeart = 20
|
|
ELIF IS_PED_SPRINTING(PLAYER_PED_ID())
|
|
fConc = 0.0
|
|
fHeart = 0
|
|
ELSE
|
|
fConc = 0.3
|
|
fHeart = 30
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Works out the current concentration value.
|
|
PROC WORK_OUT_CONCENTRATION(FLOAT &fConc, FLOAT &fHeart)
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
fConc += 0.05
|
|
fHeart += 0.05
|
|
|
|
IF fConc < 0.0
|
|
fConc = 0.0
|
|
ELIF fConc > 1.0
|
|
fConc = 1.0
|
|
ENDIF
|
|
|
|
IF fHeart < 0.0
|
|
fHeart = 0.0
|
|
ELIF fHeart > 100.0
|
|
fHeart = 100.0
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Plays the correct sfx when the player is looking down the scope.
|
|
PROC MONITER_PLAYER_AIMING_SOUNDS()
|
|
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE)
|
|
IF DOES_PLAYER_HAVE_RIFLE_EQUIPT()
|
|
AND NOT bIsPlayerOutsideHuntArea
|
|
AND IS_PLAYER_FREE_AIMING(PLAYER_ID())
|
|
AND IS_FIRST_PERSON_AIM_CAM_ACTIVE()
|
|
IF iSoundID = -1
|
|
iSoundID = GET_SOUND_ID()
|
|
ENDIF
|
|
|
|
//sniper scope take a few frames to come on screen
|
|
IF iSoundDelay >= 10
|
|
IF NOT IS_AUDIO_SCENE_ACTIVE("HUNTING_02_SETTINGS")
|
|
START_AUDIO_SCENE("HUNTING_02_SETTINGS")
|
|
WORK_OUT_INITAL_CONCENTRATION(fConcentration, fHeartBeat)
|
|
SET_AUDIO_SCENE_VARIABLE("HUNTING_02_SETTINGS","Concentration",fConcentration)
|
|
PLAY_SOUND_FROM_ENTITY(iSoundId, "Heart_Breathing", PLAYER_PED_ID())
|
|
ELSE
|
|
WORK_OUT_CONCENTRATION(fConcentration, fHeartBeat)
|
|
SET_AUDIO_SCENE_VARIABLE("HUNTING_02_SETTINGS","Concentration",fConcentration)
|
|
ENDIF
|
|
SET_VARIABLE_ON_SOUND(iSoundId, "Concentration", fHeartBeat)
|
|
ELSE
|
|
iSoundDelay++
|
|
ENDIF
|
|
ELSE
|
|
iSoundDelay = 0
|
|
RETURN_AUDIO()
|
|
ENDIF
|
|
ELSE
|
|
IF IS_AUDIO_SCENE_ACTIVE("HUNTING_02_SETTINGS")
|
|
STOP_AUDIO_SCENE("HUNTING_02_SETTINGS")
|
|
STOP_SOUND(iSoundID)
|
|
RELEASE_SOUND_ID(iSoundID)
|
|
iSoundID = -1
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Addes the vector to the points that border the hunting area.
|
|
/// PARAMS:
|
|
/// polys -
|
|
/// count -
|
|
PROC POPULATE_POLY_CHECKS(VECTOR &polys[], INT count = MAX_POLY_TEST_VERTS)
|
|
OPEN_TEST_POLY(mAreaCheck1)
|
|
|
|
INT i
|
|
FOR i = 0 TO (count-1)
|
|
ADD_TEST_POLY_VERT(mAreaCheck1, polys[i])
|
|
ENDFOR
|
|
|
|
CLOSE_TEST_POLY(mAreaCheck1)
|
|
COPY_EXPANDED_POLY(mAreaCheck2, mAreaCheck1, 50)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Monitors if the player has made any unlean kills or killed
|
|
/// elk not using a sniper rifle.
|
|
/// RETURNS:
|
|
/// TRUE if the player has made too many unclean kills.
|
|
|
|
FUNC BOOL HT_HAS_PLAYER_FAILED_HUNT()
|
|
IF bUncleanKill
|
|
OR bPlayerKillElkIncorrectly
|
|
iUncleanKills++
|
|
IF iUncleanKills >= 4
|
|
CPRINTLN(DEBUG_MISSION,"UNCLEAN FAIL!")
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Updates everything to do with the elk, controls the HUD display
|
|
/// and tracks the timers.
|
|
/// PARAMS:
|
|
/// returnTime - the time passed back to the pass/fail function
|
|
PROC UPDATE_HUNTING_ELK(BOOL bMissionEnded = FALSE, BOOL bTitleFinished = TRUE)
|
|
INT i = 0
|
|
|
|
// Pasue timer when the mission has ended or paused due to the cancel screen showing, but the HUD is still displaying.
|
|
IF NOT bPauseTimer
|
|
|
|
IF bGotPauseTime
|
|
iPauseEndTime = GET_GAME_TIMER()
|
|
iPauseDuration = iPauseEndTime - iPauseStartTime
|
|
iEndTime = iEndTime + iPauseDuration
|
|
bGotPauseTime = FALSE
|
|
ENDIF
|
|
ELSE
|
|
// If we're paused, grab the game timer and start timing the duration of the pause.
|
|
IF NOT bGotPauseTime
|
|
iPauseStartTime = (GET_GAME_TIMER())
|
|
bGotPauseTime = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Store off the player's zoom level.
|
|
fZoomLevel = 1.0
|
|
IF IS_AIM_CAM_ACTIVE()
|
|
fZoomLevel = GET_FIRST_PERSON_AIM_CAM_ZOOM_FACTOR()
|
|
ENDIF
|
|
fDistanceThreshold = DISTANCE_HARD_BLIP_THRESHOLD * fZoomLevel
|
|
|
|
// Process player calls.
|
|
CHECK_FOR_CALLS()
|
|
|
|
REPEAT MAX_ELKS i
|
|
HAS_PLAYER_KILLED_ELK(i)
|
|
CHECK_ELK_STATES(i)
|
|
ENDREPEAT
|
|
// If we've finished a random bleating cycle, extend the tim until our next random bleat.
|
|
IF bRandomBleat
|
|
bRandomBleat = FALSE
|
|
iBleatInitiateTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(BLEAT_TRIGGER_MIN_DELAY, BLEAT_TRIGGER_MAX_DELAY)
|
|
iBleatResponseTime = -1
|
|
iInitiatorIndex = -1
|
|
ENDIF
|
|
|
|
IF DOES_PLAYER_HAVE_RIFLE_EQUIPT()
|
|
bSniperEquiped = TRUE
|
|
ENDIF
|
|
|
|
|
|
// Don't show the HUD if the pause menu or quit menu is active.
|
|
IF bPauseTimer
|
|
OR IS_PHONE_ONSCREEN()
|
|
OR IS_BROWSER_OPEN()
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF NOT bMissionEnded AND bTitleFinished
|
|
SET_SNIPER_SCOPE_UNDER_HUD_THIS_FRAME()
|
|
|
|
UPDATE_WIND_BLIP(FALSE)
|
|
|
|
// Draw the next goal score here.
|
|
IF Player_Hunt_Data.iScore >= Player_Hunt_Data.iScoreForGold
|
|
IF Player_Hunt_Data.iScore > Player_Hunt_Data.iHighScore
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iScore, "AHT_HIGHSCORE", -1, HUD_COLOUR_WHITE, HUDORDER_FOURTHBOTTOM)
|
|
ELSE
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iHighScore, "AHT_HIGHSCORE", -1, HUD_COLOUR_WHITE, HUDORDER_FOURTHBOTTOM)
|
|
ENDIF
|
|
ELIF Player_Hunt_Data.iScore >= Player_Hunt_Data.iScoreForSilver
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iScoreForGold, "AHT_TGT_GOLD", -1, HUD_COLOUR_GOLD, HUDORDER_FOURTHBOTTOM)
|
|
ELIF Player_Hunt_Data.iScore >= Player_Hunt_Data.iScoreForBronze
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iScoreForSilver, "AHT_TGT_SILVER", -1, HUD_COLOUR_SILVER, HUDORDER_FOURTHBOTTOM)
|
|
ELSE
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iScoreForBronze, "AHT_TGT_BRONZE", -1, HUD_COLOUR_BRONZE, HUDORDER_FOURTHBOTTOM)
|
|
ENDIF
|
|
|
|
// Current score is bottom.
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iScore, "AHT_SCRE_UPPR", -1, HUD_COLOUR_WHITE, HUDORDER_THIRDBOTTOM)
|
|
|
|
// Current score is bottom.
|
|
DRAW_GENERIC_SCORE(Player_Hunt_Data.iMoney, "AHT_MONY_UPPR", -1, HUD_COLOUR_WHITE, HUDORDER_SECONDBOTTOM, FALSE, "HUD_CASH")
|
|
ENDIF
|
|
|
|
// We do this outside of the loop because doing it in the loop would suppress it for one elk, but that's all.
|
|
IF bShouldClearSuppressNearMissMsg
|
|
bSuppressNearMissMessage = FALSE
|
|
bShouldClearSuppressNearMissMsg = FALSE
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
|
|
|
|
|
|
|