Files
gtav-src/script/dev_ng/shared/include/public/invade_persuade_main.sch
T
2025-09-29 00:52:08 +02:00

6078 lines
270 KiB
XML
Executable File

USING "invade_persuade_using.sch"
USING "invade_persuade_drawing.sch"
// ------------------------------ HELPERS ------------------------------
/// PURPOSE:
/// Moves a float value representing a X coordinate using a speed scaled by the current stage speed
FUNC FLOAT IAP_APPLY_SPEED_TO_VALUE(FLOAT fValue, FLOAT fSpeed)
RETURN fValue +@ (fSpeed * sIAPData.fStageSpeedMod)
ENDFUNC
/// PURPOSE:
/// Moves a VECTOR_2D towards another VECTOR_2D by fDistance
FUNC VECTOR_2D IAP_MOVE_TOWARDS_VECTOR(VECTOR_2D vCurrent, VECTOR_2D vDesired, FLOAT fDistance)
VECTOR_2D vReturn
FLOAT fDistanceX = fDistance * cfBASE_SCREEN_WIDTH
fDistanceX = 0 +@ fDistanceX
FLOAT fDistanceY = fDistance * cfBASE_SCREEN_HEIGHT
fDistanceY = 0 +@ fDistanceY
vCurrent = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(vCurrent)
vDesired = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(vDesired)
FLOAT fNorm = SQRT(POW(vDesired.x - vCurrent.x, 2) + POW(vDesired.y - vCurrent.y, 2))
FLOAT fDirectionX = vDesired.x - vCurrent.x
FLOAT fDirectionY = vDesired.y - vCurrent.y
IF fNorm != 0
fDirectionX /= fNorm
fDirectionY /= fNorm
ENDIF
vReturn.x = vCurrent.x + fDistanceX * fDirectionX
vReturn.y = vCurrent.y + fDistanceY * fDirectionY
RETURN ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vReturn)
ENDFUNC
/// PURPOSE:
/// Returns the width of the pitfall sprite for the current stage
FUNC FLOAT IAP_GET_CURRENT_PITFALL_SCALE()
RETURN sIAPData.sObjectData[ENUM_TO_INT(IAP_GET_CURRENT_STAGE_PITFALL_INDEX())].vSpriteScale.x
ENDFUNC
/// PURPOSE:
/// Returns the width of the ledge sprite for the current stage
FUNC FLOAT IAP_GET_CURRENT_LEDGE_SCALE()
RETURN sIAPData.sObjectData[ENUM_TO_INT(IAP_GET_CURRENT_STAGE_LEDGE_INDEX())].vSpriteScale.x
ENDFUNC
/// PURPOSE:
/// Returns the width of the foreground sprite at iForegroundIndex
FUNC FLOAT IAP_GET_FOREGROUND_X_SCALE(INT iForegroundIndex)
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[iForegroundIndex] = ciIAP_PARALLAX_PITFALL
RETURN IAP_GET_CURRENT_PITFALL_SCALE()
ENDIF
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[iForegroundIndex] = ciIAP_PARALLAX_RAISED_LEDGE
RETURN IAP_GET_CURRENT_LEDGE_SCALE()
ENDIF
RETURN sIAPData.sCurrentStageData.vForegroundSpriteScale.x
ENDFUNC
/// PURPOSE:
/// Returns the speed boost applied when passing a drum of oil of type
FUNC FLOAT IAP_GET_SPEED_BOOST_FROM_OIL_TYPE(IAP_OBJECT eObjectType)
SWITCH eObjectType
CASE IAP_OBJECT_OIL_SMALL
RETURN cfIAP_SMALL_OIL_SPEED_BOOST
CASE IAP_OBJECT_OIL_MED_DARK
CASE IAP_OBJECT_OIL_MED_LIGHT
RETURN cfIAP_MEDIUM_OIL_SPEED_BOOST
CASE IAP_OBJECT_OIL_LARGE
RETURN cfIAP_LARGE_OIL_SPEED_BOOST
ENDSWITCH
RETURN 0.0
ENDFUNC
/// PURPOSE:
/// Returns the ground Y position at pos X
/// RETURNS:
///
FUNC FLOAT IAP_GET_GROUND_Y_AT_X_POS(FLOAT fX, BOOL bForSpawning = FALSE)
FLOAT fCurrentX = sIAPData.sParallax.fForegroundPosX[0] - (IAP_GET_FOREGROUND_X_SCALE(0)/2)
INT i
FOR i = 0 TO sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
fCurrentX += IAP_GET_FOREGROUND_X_SCALE(i)
IF fX < fCurrentX
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_PITFALL
AND (bForSpawning OR (sIAPData.sObjectInstances[sIAPData.sParallax.iLinkedObjectIndexes[i]].iFlags & ciIAP_OBJECT_FLAG_PITFALL_CRUMBLING) = 0)
IF fX > fCurrentX - IAP_GET_CURRENT_PITFALL_SCALE() + IAP_GET_CURRENT_STAGE_PITFALL_GROUND_WIDTH_LEFT()
AND fX < fCurrentX - IAP_GET_CURRENT_STAGE_PITFALL_GROUND_WIDTH_RIGHT()
//Pitfall Hole
RETURN cfIAP_PITFALL_DEPTH
ENDIF
ENDIF
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_RAISED_LEDGE
RETURN (1.0 - cfIAP_FACADE_TOP_HEIGHT) - sIAPData.sObjectData[ENUM_TO_INT(IAP_GET_CURRENT_STAGE_LEDGE_INDEX())].vSpriteScale.y + cfIAP_LEDGE_OFFSET
ENDIF
RETURN sIAPData.sCurrentStageData.fBaseY
ENDIF
ENDFOR
RETURN sIAPData.sCurrentStageData.fBaseY
ENDFUNC
FUNC BOOL SHOULD_ALLOW_IAP_IN_PROPERTY()
IF IS_PLAYER_IN_CASINO_APARTMENT(GET_PLAYER_INDEX())
RETURN TRUE
ENDIF
#IF FEATURE_CASINO_HEIST
IF IS_PLAYER_IN_ARCADE_PROPERTY(GET_PLAYER_INDEX())
RETURN TRUE
ENDIF
#ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Returns true if the game should quit
/// Processes holding a button to quit
/// RETURNS:
///
FUNC BOOL IAP_SHOULD_QUIT_NOW()
IF g_bForceQuitPenthouseArcadeMachines
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - g_bForceQuitPenthouseArcadeMachines")
RETURN TRUE
ENDIF
IF IS_PLAYER_LEAVING_ANY_SIMPLE_INTERIOR_USING_THE_LIMO_SERVICE()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - IS_PLAYER_LEAVING_ANY_SIMPLE_INTERIOR_USING_THE_LIMO_SERVICE")
RETURN TRUE
ENDIF
IF IS_PLAYER_DOING_HELI_DOCK_CUTSCENE(GET_PLAYER_INDEX())
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - IS_PLAYER_DOING_HELI_DOCK_CUTSCENE")
RETURN TRUE
ENDIF
IF NOT SHOULD_ALLOW_IAP_IN_PROPERTY()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - Not allowed in this property")
RETURN TRUE
ENDIF
IF SHOULD_KICK_PLAYER_FROM_ANY_ARCADE_GAME()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - SHOULD_KICK_PLAYER_FROM_ANY_ARCADE_GAME")
RETURN TRUE
ENDIF
IF sIAPData.eCurrentState < IAP_CLIENT_STATE_DEGENETRON
RETURN FALSE
ENDIF
CONTROL_ACTION CA_Quit = INPUT_FRONTEND_CANCEL
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_Quit = INPUT_FRONTEND_DELETE
ENDIF
IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, CA_Quit)
OR (IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_Quit))
DRAW_GENERIC_METER(ciIAP_HOLD_TO_QUIT_TIME - ABSI(NATIVE_TO_INT(GET_NETWORK_TIME()) - sIAPData.iQuitTime), ciIAP_HOLD_TO_QUIT_TIME, "DEG_GAME_QUIT")
ELSE
DRAW_GENERIC_METER(0, ciIAP_HOLD_TO_QUIT_TIME, "DEG_GAME_QUIT")
ENDIF
IF IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_Quit)
IF sIAPData.iQuitTime = -HIGHEST_INT
sIAPData.iQuitTime = NATIVE_TO_INT(GET_NETWORK_TIME()) + ciIAP_HOLD_TO_QUIT_TIME
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.iQuitTime
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - Button Held")
RETURN TRUE
ENDIF
//DRAW_GENERIC_METER(ciIAP_HOLD_TO_QUIT_TIME - (sIAPData.iQuitTime - NATIVE_TO_INT(GET_NETWORK_TIME())), ciIAP_HOLD_TO_QUIT_TIME, "IAP_EXIT", HUD_COLOUR_RED, -1, HUDORDER_TOP)
ELIF sIAPData.iQuitTime != -HIGHEST_INT
sIAPData.iQuitTime = -HIGHEST_INT
ENDIF
IF IS_PLAYER_IN_ARCADE_PROPERTY(PLAYER_ID())
IF SHOULD_KICK_PLAYER_FROM_ANY_ARCADE_GAME()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SHOULD_QUIT_NOW - SHOULD_KICK_PLAYER_FROM_ANY_ARCADE_GAME true")
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Resets the score tracking struct
/// Use when the player starts a new game from the title screen
PROC IAP_WIPE_SCORE_TRACKING_STRUCT()
sIAPData.sScoreTracking.iScoreFromPickups = 0
sIAPData.sScoreTracking.iPickupsCollected = 0
sIAPData.sScoreTracking.iTotalPickupsCollected = 0
sIAPData.sScoreTracking.iScoreFromEnemies = 0
sIAPData.sScoreTracking.iEnemiesKilled = 0
sIAPData.sScoreTracking.iTotalEnemiesKilled = 0
sIAPData.sScoreTracking.iTotalAnimalsKilled = 0
sIAPData.sScoreTracking.iScoreFromOil = 0
sIAPData.sScoreTracking.iOilCollected = 0
sIAPData.sScoreTracking.iTotalOilCollected = 0
sIAPData.sScoreTracking.iScoreFromDistance = 0
sIAPData.sScoreTracking.iScoreFromLives = 0
sIAPData.sScoreTracking.iScoreFromArmour = 0
ENDPROC
// ------------------------------ LEADERBOARD ------------------------------
/// PURPOSE:
/// Returns the default initials for a leaderboard position
FUNC INT IAP_GET_DEFAULT_INITIALS_FOR_POSITION(INT iPosition)
SWITCH iPosition
CASE 0 RETURN 54161 //RON
CASE 1 RETURN 1172 //USA
CASE 2 RETURN 45582 //OIL
CASE 3 RETURN 70801 //RSR
CASE 4 RETURN 5199 //PRB
CASE 5 RETURN 12994 //CLD
CASE 6 RETURN 4613 //FIB
CASE 7 RETURN 73734 //GAS
CASE 8 RETURN 8256 //ABC
CASE 9 RETURN 13078 //WMD
ENDSWITCH
RETURN 0
ENDFUNC
/// PURPOSE:
/// Returns the default score for a leaderboard position
FUNC INT IAP_GET_DEFAULT_SCORE_FOR_POSITION(INT iPosition)
SWITCH iPosition
CASE 0 RETURN 2273775
CASE 1 RETURN 2000000
CASE 2 RETURN 1900000
CASE 3 RETURN 1800000
CASE 4 RETURN 1700000
CASE 5 RETURN 1600000
CASE 6 RETURN 1500000
CASE 7 RETURN 1400000
CASE 8 RETURN 1200000
CASE 9 RETURN 1000000
ENDSWITCH
RETURN 0
ENDFUNC
/// PURPOSE:
/// Initialise the leaderboard data
PROC IAP_INITIALISE_LEADERBOARD(INT &iInitials[ciCASINO_ARCADE_LEADERBOARD_POSITIONS], INT &iScores[ciCASINO_ARCADE_LEADERBOARD_POSITIONS])
INT i
FOR i = 0 TO ciCASINO_ARCADE_LEADERBOARD_POSITIONS - 1
IF iScores[i] <= 0
//First time - Initialise
sIAPData.sLeaderboard[i].iScore = IAP_GET_DEFAULT_SCORE_FOR_POSITION(i)
sIAPData.sLeaderboard[i].iInitials = IAP_GET_DEFAULT_INITIALS_FOR_POSITION(i)
BROADCAST_CASINO_ARCADE_UPDATE_LEADERBOARD_EVENT(GET_OWNER_OF_SIMPLE_INTERIOR_PLAYER_IS_IN(PLAYER_ID()), CASINO_ARCADE_GAME_INVADE_PERSUADE, i, sIAPData.sLeaderboard[i].iInitials, sIAPData.sLeaderboard[i].iScore)
ELSE
sIAPData.sLeaderboard[i].iScore = iScores[i]
sIAPData.sLeaderboard[i].iInitials = iInitials[i]
ENDIF
ENDFOR
sIAPData.bLeaderboardRecieved = TRUE
ENDPROC
PROC IAP_QUICK_SORT_LEADERBOARD(IAP_LEADERBOARD_STRUCT &sArray[], INT iLeft, INT iRight)
INT i, j
INT p = sArray[((iLeft + iRight) / 2)].iScore
IAP_LEADERBOARD_STRUCT q
i = iLeft
j = iRight
WHILE (i <= j)
WHILE ((sArray[i].iScore > p) AND (i < iRight))
i++
ENDWHILE
WHILE ((p > sArray[j].iScore) AND (j > iLeft))
j--
ENDWHILE
IF (i <= j)
q.iInitials = sArray[i].iInitials
q.bPlayer = sArray[i].bPlayer
q.iScore = sArray[i].iScore
sArray[i].iInitials = sArray[j].iInitials
sArray[i].bPlayer = sArray[j].bPlayer
sArray[i].iScore = sArray[j].iScore
sArray[j].iInitials = q.iInitials
sArray[j].bPlayer = q.bPlayer
sArray[j].iScore = q.iScore
i++
j--
ENDIF
ENDWHILE
IF (i < iRight)
IAP_QUICK_SORT_LEADERBOARD(sArray, i, iRight)
ENDIF
IF (iLeft < j)
IAP_QUICK_SORT_LEADERBOARD(sArray, iLeft, j)
ENDIF
ENDPROC
/// PURPOSE:
/// Sorts the leaderboard once players' final scores are set
PROC IAP_SORT_LEADERBOARD()
IAP_LEADERBOARD_STRUCT sTempArray[ciCASINO_ARCADE_LEADERBOARD_POSITIONS + 1]
INT i
FOR i = 0 TO ciCASINO_ARCADE_LEADERBOARD_POSITIONS - 1
sTempArray[i].iInitials = sIAPData.sLeaderboard[i].iInitials
sTempArray[i].bPlayer = FALSE
sTempArray[i].iScore = sIAPData.sLeaderboard[i].iScore
ENDFOR
IF !sIAPData.bCheated
sTempArray[ciCASINO_ARCADE_LEADERBOARD_POSITIONS].bPlayer = TRUE
sTempArray[ciCASINO_ARCADE_LEADERBOARD_POSITIONS].iScore = IAP_GET_CURRENT_SCORE()
sTempArray[ciCASINO_ARCADE_LEADERBOARD_POSITIONS].iInitials = 0
ENDIF
IAP_QUICK_SORT_LEADERBOARD(sTempArray, 0, ciCASINO_ARCADE_LEADERBOARD_POSITIONS)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SORT_LEADERBOARD - Sorting")
FOR i = 0 TO ciCASINO_ARCADE_LEADERBOARD_POSITIONS - 1
sIAPData.sLeaderboard[i].iInitials = sTempArray[i].iInitials
sIAPData.sLeaderboard[i].bPlayer = sTempArray[i].bPlayer
sIAPData.sLeaderboard[i].iScore = sTempArray[i].iScore
BROADCAST_CASINO_ARCADE_UPDATE_LEADERBOARD_EVENT(GET_OWNER_OF_SIMPLE_INTERIOR_PLAYER_IS_IN(PLAYER_ID()), CASINO_ARCADE_GAME_INVADE_PERSUADE, i, sIAPData.sLeaderboard[i].iInitials, sIAPData.sLeaderboard[i].iScore)
ENDFOR
ENDPROC
PROC IAP_PROCESS_LEADERBOARD_ENTRY()
IF IAP_GET_PLAYER_LEADERBOARD_POSITION() >= ciCASINO_ARCADE_LEADERBOARD_POSITIONS
EXIT
ENDIF
INT iUnpackedInitials[ciARCADE_CABINET_LEADERBOARD_INITIALS]
IF SC_PROFANITY_GET_CHECK_IS_VALID(sIAPData.iLbdInitialProfanityToken)
IF SC_PROFANITY_GET_CHECK_IS_PENDING(sIAPData.iLbdInitialProfanityToken)
EXIT
ENDIF
IF SC_PROFANITY_GET_STRING_PASSED(sIAPData.iLbdInitialProfanityToken)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_LEADERBOARD_ENTRY - Profanity: Initials OK")
sIAPData.sLeaderboard[IAP_GET_PLAYER_LEADERBOARD_POSITION()].iInitials = sIAPData.iInitials
BROADCAST_CASINO_ARCADE_UPDATE_LEADERBOARD_EVENT(GET_OWNER_OF_SIMPLE_INTERIOR_PLAYER_IS_IN(PLAYER_ID()), CASINO_ARCADE_GAME_INVADE_PERSUADE, IAP_GET_PLAYER_LEADERBOARD_POSITION(), sIAPData.sLeaderboard[IAP_GET_PLAYER_LEADERBOARD_POSITION()].iInitials, sIAPData.sLeaderboard[IAP_GET_PLAYER_LEADERBOARD_POSITION()].iScore)
sIAPData.iLbdInitialProfanityToken = 0
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_LEADERBOARD_ENTRY - Profanity: Initials BAD")
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Change_Letter")
sIAPData.iCurrentInitial = 0
sIAPData.iInitials = 0
sIAPData.iLbdInitialProfanityToken = 0
ENDIF
EXIT
ENDIF
IF sIAPData.iCurrentInitial >= ciARCADE_CABINET_LEADERBOARD_INITIALS - 1
EXIT
ENDIF
CONTROL_ACTION CA_InitialUp = INPUT_SCRIPT_RB
CONTROL_ACTION CA_InitialDown = INPUT_SCRIPT_LB
CONTROL_ACTION CA_InitialAccept = INPUT_FRONTEND_RDOWN
CONTROL_ACTION CA_InitialBack = INPUT_FRONTEND_RRIGHT
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_InitialAccept = INPUT_CURSOR_ACCEPT
CA_InitialBack = INPUT_CURSOR_CANCEL
CA_InitialUp = INPUT_FRONTEND_UP
CA_InitialDown = INPUT_FRONTEND_DOWN
ENDIF
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_InitialAccept)
sIAPData.iCurrentInitial ++
IF sIAPData.iCurrentInitial >= ciARCADE_CABINET_LEADERBOARD_INITIALS - 1
sIAPData.iCurrentInitial = ciARCADE_CABINET_LEADERBOARD_INITIALS - 1
ARCADE_UNPACK_LEADERBOARD_INITIALS(sIAPData.iInitials, iUnpackedInitials)
TEXT_LABEL_3 tl3Initials = ARCADE_GET_CHAR_FROM_INT(iUnpackedInitials[0])
tl3Initials += ARCADE_GET_CHAR_FROM_INT(iUnpackedInitials[1])
tl3Initials += ARCADE_GET_CHAR_FROM_INT(iUnpackedInitials[2])
IF SC_PROFANITY_CHECK_STRING(tl3Initials, sIAPData.iLbdInitialProfanityToken)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_LEADERBOARD_ENTRY - Profanity: Starting check")
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Entered_Score")
ENDIF
ENDIF
EXIT
ENDIF
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_InitialBack)
IF sIAPData.iCurrentInitial > 0
sIAPData.iCurrentInitial --
ENDIF
EXIT
ENDIF
INT iDelta = 0
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_InitialUp)
iDelta = 1
ELIF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_InitialDown)
iDelta = -1
ENDIF
IF iDelta = 0
EXIT
ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Change_Letter")
ARCADE_UNPACK_LEADERBOARD_INITIALS(sIAPData.iInitials, iUnpackedInitials)
iUnpackedInitials[sIAPData.iCurrentInitial] += iDelta
IF iUnpackedInitials[sIAPData.iCurrentInitial] >= ciARCADE_CABINET_LEADERBOARD_INITIALS_MAX
iUnpackedInitials[sIAPData.iCurrentInitial] = 0
ELIF iUnpackedInitials[sIAPData.iCurrentInitial] < 0
iUnpackedInitials[sIAPData.iCurrentInitial] = ciARCADE_CABINET_LEADERBOARD_INITIALS_MAX - 1
ENDIF
sIAPData.iInitials = ARCADE_PACK_LEADERBOARD_INITIALS(iUnpackedInitials)
ENDPROC
// ------------------------------ HELP TEXT ------------------------------
/// PURPOSE:
/// Returns whether or not the help text is on display
FUNC BOOL IAP_IS_THIS_HELP_BEING_DISPLAYED(STRING stHelp)
IF sIAPData.iDisplayedHelpText = GET_HASH_KEY(stHelp)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Prints a help text string and sets iDisplayedHelpText
/// PARAMS:
/// stHelp -
PROC IAP_PRINT_HELP_FOREVER(STRING stHelp)
sIAPData.iDisplayedHelpText = GET_HASH_KEY(stHelp)
PRINT_HELP_FOREVER(stHelp)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] SCGW_PRINT_HELP_FOREVER - Printing ", stHelp, "(",sIAPData.iDisplayedHelpText,")")
ENDPROC
/// PURPOSE:
/// Prints a help text string with a number and sets iDisplayedHelpText
/// PARAMS:
/// stHelp -
PROC IAP_PRINT_HELP_FOREVER_WITH_NUMBER(STRING stHelp, INT iValue)
sIAPData.iDisplayedHelpText = GET_HASH_KEY(stHelp)
PRINT_HELP_WITH_NUMBER(stHelp, iValue)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PRINT_HELP_FOREVER_WITH_NUMBER - Printing ", stHelp, "(",sIAPData.iDisplayedHelpText,")")
ENDPROC
/// PURPOSE:
/// Clears help text and resets stCurrentHelpText & iCurrentHelpTextExpiry to stop it being redrawn
PROC IAP_CLEAR_HELP_TEXT()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CLEAR_HELP_TEXT - Clearing")
DEBUG_PRINTCALLSTACK()
sIAPData.iDisplayedHelpText = -1
IF sIAPData.iCurrentHelpTextExpiry != -HIGHEST_INT
sIAPData.iCurrentHelpTextExpiry = -HIGHEST_INT
ENDIF
IF NOT IS_STRING_NULL_OR_EMPTY(sIAPData.stCurrentHelpText)
sIAPData.stCurrentHelpText = ARCADE_GET_NULL_STRING()
ENDIF
IF IS_HELP_MESSAGE_BEING_DISPLAYED()
CLEAR_HELP()
ENDIF
ENDPROC
/// PURPOSE:
/// Draws start/quit helptext on the title screen
PROC IAP_PROCESS_TITLE_SCREEN_HELP_TEXT()
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHOWING_HELP_TEXT)
TEXT_LABEL_15 stHelp = "IAP_H_TITLE"
IF IS_PLAYSTATION_PLATFORM()
stHelp += "_PS4"
ELIF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
stHelp += "_PC"
ENDIF
IF IAP_IS_THIS_HELP_BEING_DISPLAYED(stHelp)
EXIT
ENDIF
IAP_CLEAR_HELP_TEXT()
IAP_PRINT_HELP_FOREVER(stHelp)
ENDPROC
/// PURPOSE:
/// Draws the leaderboard help text
PROC IAP_PROCESS_LEADERBOARD_HELP_TEXT()
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHOWING_HELP_TEXT)
TEXT_LABEL_15 stHelp
IF IAP_GET_PLAYER_LEADERBOARD_POSITION() = ciIAP_LBD_DEFAULT_RANK
OR sIAPData.iCurrentInitial > ciARCADE_CABINET_LEADERBOARD_INITIALS - 2
stHelp = "IAP_H_LBD0"
IF IS_PLAYSTATION_PLATFORM()
stHelp += "_PS4"
ENDIF
ELIF sIAPData.iCurrentInitial = ciARCADE_CABINET_LEADERBOARD_INITIALS - 2
stHelp = "IAP_H_LBD1"
ELSE
stHelp = "IAP_H_LBD2"
ENDIF
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
stHelp += "_PC"
ENDIF
IF IAP_IS_THIS_HELP_BEING_DISPLAYED(stHelp)
EXIT
ENDIF
IAP_CLEAR_HELP_TEXT()
IAP_PRINT_HELP_FOREVER(stHelp)
ENDPROC
/// PURPOSE:
/// Draws help text for spawned objects
PROC IAP_PROCESS_OBJECT_HELP_TEXT()
IF sIAPData.iCurrentHelpTextExpiry = -HIGHEST_INT
EXIT
ENDIF
IF IS_STRING_NULL_OR_EMPTY(sIAPData.stCurrentHelpText)
EXIT
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.iCurrentHelpTextExpiry
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_OBJECT_HELP_TEXT - Text: ", sIAPData.stCurrentHelpText, " has expired")
IAP_CLEAR_HELP_TEXT()
EXIT
ENDIF
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHOWING_HELP_TEXT)
TEXT_LABEL_15 stHelp = sIAPData.stCurrentHelpText
IF sIAPData.iCurrentHelpTextValue = -1
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
stHelp += "_PC"
ENDIF
ELSE
IF IAP_IS_THIS_HELP_BEING_DISPLAYED(stHelp)
EXIT
ENDIF
IAP_PRINT_HELP_FOREVER_WITH_NUMBER(stHelp, sIAPData.iCurrentHelpTextValue)
EXIT
ENDIF
IF IAP_IS_THIS_HELP_BEING_DISPLAYED(stHelp)
EXIT
ENDIF
IAP_PRINT_HELP_FOREVER(stHelp)
ENDPROC
/// PURPOSE:
/// Triggers help text from a spawned object
PROC IAP_TRIGGER_OBJECT_HELP_TEXT(STRING stHelpText, INT iDuration)
IAP_CLEAR_HELP_TEXT()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_OBJECT_HELP_TEXT - Triggering: ", stHelpText, " Duration: ", iDuration)
sIAPData.iCurrentHelpTextExpiry = NATIVE_TO_INT(GET_NETWORK_TIME()) + iDuration
sIAPData.stCurrentHelpText = stHelpText
sIAPData.iCurrentHelpTextValue = -1
ENDPROC
/// PURPOSE:
/// Triggers help text for completing a challenge
PROC IAP_TRIGGER_CHALLENGE_HELP_TEXT(STRING stHelpText, INT iValue, INT iDuration)
IAP_CLEAR_HELP_TEXT()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_CHALLENGE_HELP_TEXT - Triggering: ", stHelpText, " iValue = ", iValue, " Duration: ", iDuration)
sIAPData.iCurrentHelpTextExpiry = NATIVE_TO_INT(GET_NETWORK_TIME()) + iDuration
sIAPData.stCurrentHelpText = stHelpText
sIAPData.iCurrentHelpTextValue = iValue
ENDPROC
/// PURPOSE:
/// Returns whether or not help text is being drawn by the minigame this frame
FUNC BOOL IAP_SHOULD_ALLOW_HELP_TEXT_THIS_FRAME()
RETURN IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHOWING_HELP_TEXT)
ENDFUNC
// ------------------------------ CHALLENGES ------------------------------
PROC IAP_TRIGGER_AWARD_TICKERS()
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_KILL_CHALLENGE_UNLOCKED_THIS_GAME)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_AWARD_TICKERS - Kill Challenge Ticker")
SET_REWARD_UNLOCKED(UNLOCKTYPEENUM_TATTOO, "CLO_VWM_U_23_1", "UNLOCK_NAME_SHIRT3","FeedhitTshirt04","MPTshirtAwards3" ,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,TRUE)
ENDIF
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_OIL_CHALLENGE_UNLOCKED_THIS_GAME)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_AWARD_TICKERS - Oil Challenge Ticker")
SET_REWARD_UNLOCKED(UNLOCKTYPEENUM_TATTOO, "CLO_VWM_U_23_3", "UNLOCK_NAME_SHIRT3","FeedhitTshirt04","MPTshirtAwards3" ,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,TRUE)
ENDIF
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_MOON_DISTANCE_UNLOCKED_THIS_GAME)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_AWARD_TICKERS - Moon Challenge Ticker")
SET_REWARD_UNLOCKED(UNLOCKTYPEENUM_TATTOO, "CLO_VWM_D_1_10", "UNLOCK_NAME_SHIRT3","FeedhitTshirt04","MPTshirtAwards3" ,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,TRUE)
ENDIF
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_LIVES_CHALLENGE_UNLOCKED_THIS_GAME)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_AWARD_TICKERS - Lives Challenge Ticker")
SET_REWARD_UNLOCKED(UNLOCKTYPEENUM_TATTOO, "CLO_VWM_U_23_6", "UNLOCK_NAME_SHIRT3","FeedhitTshirt04","MPTshirtAwards3" ,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,TRUE)
ENDIF
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_SCORE_CHALLENGE_UNLOCKED_THIS_GAME)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_TRIGGER_AWARD_TICKERS - Score Challenge Ticker")
SET_REWARD_UNLOCKED(UNLOCKTYPEENUM_TATTOO, "CLO_VWM_D_1_9", "UNLOCK_NAME_SHIRT3","FeedhitTshirt04","MPTshirtAwards3" ,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,TRUE)
ENDIF
ENDPROC
PROC IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED()
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_GOLDEN_TANK_UNLOCKED)
//Already unlocked
EXIT
ENDIF
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_GOLDEN_TANK_UNLOCKED_THIS_GAME)
//Already unlocked but not applied this game
EXIT
ENDIF
IF g_sMPtunables.bVC_IAP_KILL_CHALLENGE_REQUIRED_FOR_GOLD
AND NOT IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_KILL_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF g_sMPtunables.bVC_IAP_OIL_CHALLENGE_REQUIRED_FOR_GOLD
AND NOT IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_OIL_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF g_sMPtunables.bVC_IAP_MOON_DISTANCE_CHALLENGE_REQUIRED_FOR_GOLD
AND NOT IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_MOON_DISTANCE_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF g_sMPtunables.bVC_IAP_LIVES_CHALLENGE_REQUIRED_FOR_GOLD
AND NOT IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_LIVES_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF g_sMPtunables.bVC_IAP_SCORE_CHALLENGE_REQUIRED_FOR_GOLD
AND NOT IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_SCORE_CHALLENGE_COMPLETE)
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED - Golden Tank Unlock Requirements Met")
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_GOLD_TANK, TRUE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_GOLDEN_TANK_UNLOCKED_THIS_GAME)
ENDPROC
PROC IAP_UPDATE_KILL_CHALLENGE(#IF IS_DEBUG_BUILD BOOL bForce = FALSE #ENDIF)
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_KILL_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF sIAPData.sScoreTracking.iTotalAnimalsKilled < g_sMPtunables.iVC_IAP_KILL_CHALLENGE_REQUIREMENT
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_UPDATE_KILL_CHALLENGE - Kill Challenge Complete")
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_0, TRUE)
SET_PACKED_STAT_BOOL(PACKED_MP_UNNATURAL_SELECTION, TRUE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_KILL_CHALLENGE_COMPLETE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_KILL_CHALLENGE_UNLOCKED_THIS_GAME)
IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED()
IAP_TRIGGER_CHALLENGE_HELP_TEXT("IAP_CH_0", g_sMPtunables.iVC_IAP_KILL_CHALLENGE_REQUIREMENT, ciIAP_DEFAULT_HELP_TEXT_TIME)
ENDPROC
PROC IAP_UPDATE_OIL_CHALLENGE(#IF IS_DEBUG_BUILD BOOL bForce = FALSE #ENDIF)
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_OIL_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF sIAPData.sScoreTracking.iTotalOilCollected < g_sMPtunables.iVC_IAP_OIL_CHALLENGE_REQUIREMENT
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_UPDATE_OIL_CHALLENGE - Oil Challenge Complete")
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_1, TRUE)
SET_PACKED_STAT_BOOL(PACKED_MP_ENDLESS_OIL, TRUE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_OIL_CHALLENGE_COMPLETE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_OIL_CHALLENGE_UNLOCKED_THIS_GAME)
IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED()
IAP_TRIGGER_CHALLENGE_HELP_TEXT("IAP_CH_1", g_sMPtunables.iVC_IAP_OIL_CHALLENGE_REQUIREMENT, ciIAP_DEFAULT_HELP_TEXT_TIME)
ENDPROC
PROC IAP_UPDATE_MAX_MOON_DISTANCE(#IF IS_DEBUG_BUILD BOOL bForce = FALSE #ENDIF)
IF sIAPData.eCurrentStage != IAP_STAGE_MOON
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
//Distance
INT iDistanceTravelled = FLOOR(sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION)
IF (iDistanceTravelled > sIAPData.iCachedMaxMoonDistance)
sIAPData.iCachedMaxMoonDistance = iDistanceTravelled
ENDIF
//Challenge
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_MOON_DISTANCE_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF iDistanceTravelled < g_sMPtunables.iVC_IAP_MOON_DISTANCE_CHALLENGE_REQUIREMENT
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_UPDATE_MAX_MOON_DISTANCE - Moon Distance Challenge Complete")
SET_PACKED_STAT_BOOL(PACKED_MP_FULL_MOON, TRUE)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_2, TRUE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_MOON_DISTANCE_CHALLENGE_COMPLETE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_MOON_DISTANCE_UNLOCKED_THIS_GAME)
IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED()
IAP_TRIGGER_CHALLENGE_HELP_TEXT("IAP_CH_2", g_sMPtunables.iVC_IAP_MOON_DISTANCE_CHALLENGE_REQUIREMENT, ciIAP_DEFAULT_HELP_TEXT_TIME)
ENDPROC
PROC IAP_UPDATE_LIVES_CHALLENGE(#IF IS_DEBUG_BUILD BOOL bForce = FALSE #ENDIF)
IF sIAPData.bCheated
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_LIVES_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF sIAPData.sPlayerTank.iLives < g_sMPtunables.iVC_IAP_LIVES_CHALLENGE_REQUIREMENT
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_UPDATE_LIVES_CHALLENGE - Lives Challenge Complete")
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_3, TRUE)
SET_PACKED_STAT_BOOL(PACKED_MP_LIFE_SAVER, TRUE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_LIVES_CHALLENGE_COMPLETE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_LIVES_CHALLENGE_UNLOCKED_THIS_GAME)
IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED()
IAP_TRIGGER_CHALLENGE_HELP_TEXT("IAP_CH_3", g_sMPtunables.iVC_IAP_LIVES_CHALLENGE_REQUIREMENT, ciIAP_DEFAULT_HELP_TEXT_TIME)
ENDPROC
PROC IAP_UPDATE_SCORE_CHALLENGE(#IF IS_DEBUG_BUILD BOOL bForce = FALSE #ENDIF)
IF IS_BIT_SET(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_SCORE_CHALLENGE_COMPLETE)
EXIT
ENDIF
IF sIAPData.iScoreToShow < g_sMPtunables.iVC_IAP_SCORE_CHALLENGE_REQUIREMENT
#IF IS_DEBUG_BUILD
AND NOT bForce
#ENDIF
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_UPDATE_SCORE_CHALLENGE - Score Challenge Complete")
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_4, TRUE)
SET_PACKED_STAT_BOOL(PACKED_MP_HE_WHO_CONTROLS_THE_OIL, TRUE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_SCORE_CHALLENGE_COMPLETE)
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_SCORE_CHALLENGE_UNLOCKED_THIS_GAME)
IAP_CHECK_IF_GOLDEN_TANK_UNLOCKED()
IAP_TRIGGER_CHALLENGE_HELP_TEXT("IAP_CH_4", g_sMPtunables.iVC_IAP_SCORE_CHALLENGE_REQUIREMENT, ciIAP_DEFAULT_HELP_TEXT_TIME)
ENDPROC
PROC IAP_INITIALISE_CHALLENGE_COMPLETION()
IF GET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_GOLD_TANK)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Golden Tank Unlocked")
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_GOLDEN_TANK_UNLOCKED)
ENDIF
IF GET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_0)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Kill Challenge Complete")
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_KILL_CHALLENGE_COMPLETE)
ENDIF
IF GET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_1)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Oil Challenge Complete")
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_OIL_CHALLENGE_COMPLETE)
ENDIF
IF GET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_2)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Moon Distance Challenge Complete")
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_MOON_DISTANCE_CHALLENGE_COMPLETE)
ENDIF
IF GET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_3)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Lives Challenge Complete")
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_LIVES_CHALLENGE_COMPLETE)
ENDIF
IF GET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_4)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Score Challenge Complete")
SET_BIT(sIAPData.iChallengeBitSet, ciIAP_CHALLENGEBS_SCORE_CHALLENGE_COMPLETE)
ENDIF
sIAPData.iCachedMaxMoonDistance = GET_MP_INT_CHARACTER_STAT(MP_STAT_IAP_MAX_MOON_DIST)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_CHALLENGE_COMPLETION - Moon Distance = ", sIAPData.iCachedMaxMoonDistance)
ENDPROC
// ------------------------------ CHEATING ------------------------------
FUNC CONTROL_ACTION IAP_GET_NEXT_CHEAT_INPUT()
SWITCH sIAPData.iCheatInputProgress
CASE ciIAP_CHEAT_PROGRESS_UP_1
CASE ciIAP_CHEAT_PROGRESS_UP_2
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
RETURN INPUT_FRONTEND_UP
ELSE
RETURN INPUT_SCRIPT_PAD_UP
ENDIF
BREAK
CASE ciIAP_CHEAT_PROGRESS_DOWN_1
CASE ciIAP_CHEAT_PROGRESS_DOWN_2
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
RETURN INPUT_FRONTEND_DOWN
ELSE
RETURN INPUT_SCRIPT_PAD_DOWN
ENDIF
BREAK
CASE ciIAP_CHEAT_PROGRESS_LEFT_1
CASE ciIAP_CHEAT_PROGRESS_LEFT_2
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
RETURN INPUT_FRONTEND_LEFT
ELSE
RETURN INPUT_SCRIPT_PAD_LEFT
ENDIF
BREAK
CASE ciIAP_CHEAT_PROGRESS_RIGHT_1
CASE ciIAP_CHEAT_PROGRESS_RIGHT_2
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
RETURN INPUT_FRONTEND_RIGHT
ELSE
RETURN INPUT_SCRIPT_PAD_RIGHT
ENDIF
BREAK
CASE ciIAP_CHEAT_PROGRESS_B
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
RETURN INPUT_CURSOR_CANCEL
ELSE
RETURN INPUT_SCRIPT_RRIGHT
ENDIF
BREAK
CASE ciIAP_CHEAT_PROGRESS_A
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
RETURN INPUT_CURSOR_ACCEPT
ELSE
RETURN INPUT_SCRIPT_RDOWN
ENDIF
BREAK
ENDSWITCH
RETURN MAX_INPUTS
ENDFUNC
PROC IAP_PROCESS_CHEATING()
IF sIAPData.iCheatInputTime != -HIGHEST_INT
AND NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.iCheatInputTime
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_CHEATING - Cheat time expired - iCheatInputProgress = ", sIAPData.iCheatInputProgress)
sIAPData.iCheatInputTime = -HIGHEST_INT
sIAPData.iCheatInputProgress = 0
ENDIF
CONTROL_ACTION CA_NextCheat = IAP_GET_NEXT_CHEAT_INPUT()
IF CA_NextCheat = MAX_INPUTS
EXIT
ENDIF
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_NextCheat)
sIAPData.iCheatInputTime = NATIVE_TO_INT(GET_NETWORK_TIME()) + ciIAP_CHEAT_TIMEOUT_DELAY
sIAPData.iCheatInputProgress ++
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_CHEATING - iCheatInputProgress = ", sIAPData.iCheatInputProgress)
ENDIF
IF sIAPData.iCheatInputProgress >= ciIAP_CHEAT_PROGRESS_COMPLETE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_CHEATING - CHEAT ACTIVE")
sIAPData.bCheated = TRUE
sIAPData.sPlayerTank.iLives = ciIAP_STARTING_LIVES_CHEATED
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Retry")
sIAPData.iCheatInputTime = -HIGHEST_INT
sIAPData.iCheatInputProgress = 0
ENDIF
ENDPROC
// ------------------------------ NUKE ------------------------------
/// PURPOSE:
/// STARTS A NUCLEAR STRIKE
PROC IAP_NUKE_SCREEN()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_NUKE_SCREEN - NUCLEAR STRIKE APPROACHING")
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Tank_Weapon_Nuke_Blast", "dlc_vw_am_ip_tank_sounds", INIT_VECTOR_2D(cfSCREEN_CENTER, cfSCREEN_CENTER))
REINIT_NET_TIMER(sIAPData.tdNukeTimer)
ENDPROC
/// PURPOSE:
/// Returns true if the object type is not destroyed by nukes
FUNC BOOL IAP_IS_OBJECT_TYPE_NUKE_PROOF(IAP_OBJECT_TYPE eObjectType)
IF eObjectType = IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
OR eObjectType = IAP_OBJECT_TYPE_PITFALL
OR eObjectType = IAP_OBJECT_TYPE_LEDGE
OR eObjectType = IAP_OBJECT_TYPE_PICKUP
OR eObjectType = IAP_OBJECT_TYPE_OIL
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
// ------------------------------ FLOATING TEXT ------------------------------
/// PURPOSE:
/// Starts flashing floating text showing score at a location on screen
PROC IAP_ADD_SCORE_TEXT(INT iScore, VECTOR_2D vPos)
sIAPData.sScoreText[sIAPData.iNextScoreTextIndex].iStartTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sScoreText[sIAPData.iNextScoreTextIndex].iScore = iScore
sIAPData.sScoreText[sIAPData.iNextScoreTextIndex].vPos = vPos
sIAPData.iNextScoreTextIndex++
IF sIAPData.iNextScoreTextIndex >= ciIAP_MAX_SCORE_TEXT
sIAPData.iNextScoreTextIndex = 0
ENDIF
ENDPROC
/// PURPOSE:
/// Starts flashing floating text above the player's tank
PROC IAP_ADD_ABOVE_PLAYER_TEXT(STRING tl63Text)
sIAPData.sPlayerTank.sAbovePlayerText.iStartTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sPlayerTank.sAbovePlayerText.tl63Text = tl63Text
ENDPROC
PROC IAP_PROCESS_SCORE_TEXT()
INT i
FOR i = 0 TO ciIAP_MAX_SCORE_TEXT - 1
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sScoreText[i].iStartTime + ciIAP_SCORE_TEXT_DURATION
RELOOP
ENDIF
IF sIAPData.eCurrentState = IAP_CLIENT_STATE_RUNNING
sIAPData.sScoreText[i].vPos.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sScoreText[i].vPos.x, CFIAP_BASE_FOREGROUND_SPEED)
ENDIF
ENDFOR
ENDPROC
// ------------------------------ SCORING ------------------------------
/// PURPOSE:
/// Adds to the player's score and keeps track of what it was added for
/// Triggers floating text if relevant to the scoring type
PROC IAP_ADD_SCORE(INT iScoreToAdd, IAP_SCORE_TYPE eScoreType, VECTOR_2D vScorePos)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_ADD_SCORE - iScoreToAdd: ", iScoreToAdd, " type: ", IAP_DEBUG_GET_IAP_SCORE_TYPE_AS_STRING(eScoreType))
SWITCH eScoreType
CASE IAP_SCORE_TYPE_ENEMY
sIAPData.sScoreTracking.iScoreFromEnemies += iScoreToAdd
sIAPData.sScoreTracking.iEnemiesKilled ++
sIAPData.sScoreTracking.iTotalEnemiesKilled ++
IAP_ADD_SCORE_TEXT(iScoreToAdd, vScorePos)
IAP_UPDATE_KILL_CHALLENGE()
BREAK
CASE IAP_SCORE_TYPE_PICKUP
sIAPData.sScoreTracking.iScoreFromPickups += iScoreToAdd
BREAK
CASE IAP_SCORE_TYPE_OIL
sIAPData.sScoreTracking.iScoreFromOil += iScoreToAdd
sIAPData.sScoreTracking.iOilCollected ++
sIAPData.sScoreTracking.iTotalOilCollected ++
IAP_ADD_SCORE_TEXT(iScoreToAdd, vScorePos)
IAP_UPDATE_OIL_CHALLENGE()
BREAK
CASE IAP_SCORE_TYPE_DISTANCE
sIAPData.sScoreTracking.iScoreFromDistance += iScoreToAdd
BREAK
CASE IAP_SCORE_TYPE_ARMOUR
sIAPData.sScoreTracking.iScoreFromArmour += iScoreToAdd
BREAK
CASE IAP_SCORE_TYPE_LIVES
sIAPData.sScoreTracking.iScoreFromLives += iScoreToAdd
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Calculates the players score and updates iScoreToShow
PROC IAP_PROCESS_PLAYER_SCORE()
INT iActualScore = IAP_GET_CURRENT_SCORE()
INT iDelta = iActualScore - sIAPData.iScoreToShow
IF iDelta = 0
EXIT
ENDIF
INT iFrameTime = ROUND(GET_FRAME_TIME() * 1000)
INT iScoreToAdd = iFrameTime * PICK_INT(sIAPData.eCurrentState = IAP_CLIENT_STATE_STAGE_OUTRO, ciIAP_SCORE_PER_MS_OUTRO, ciIAP_SCORE_PER_MS)
IF sIAPData.eCurrentState = IAP_CLIENT_STATE_STAGE_OUTRO
AND NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SCORE_TALLY_STARTED)
//Boost through the massive end oil score
iScoreToAdd *= ciIAP_SCORE_END_OIL_SPEED_MULTIPLIER
ENDIF
IF iScoreToAdd > iDelta
iScoreToAdd = iDelta
ENDIF
sIAPData.iScoreToShow += iScoreToAdd
IAP_UPDATE_SCORE_CHALLENGE()
ENDPROC
/// PURPOSE:
/// Returns true when the player's final score has been tallied up
/// RETURNS:
///
FUNC BOOL IAP_PROCESSED_FINAL_STAGE_SCORE()
IF sIAPData.iMiddleTextAnimFrame < IAP_GET_MIDDLE_TEXT_SEQUENCE_FRAMES(IAP_MIDDLE_TEXT_SEQ_STAGE_CLEARED) + ciIAP_STAGE_CLEAR_TALLY_DELAY_FRAMES + ciIAP_STAGE_CLEAR_SCALE_UP_FRAMES
RETURN FALSE
ENDIF
CONTROL_ACTION CA_Skip = INPUT_SCRIPT_RDOWN
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_Skip = INPUT_CURSOR_ACCEPT
ENDIF
BOOL bSkipPressed = IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_Skip)
IF bSkipPressed
sIAPData.iScoreToShow = IAP_GET_CURRENT_SCORE()
ENDIF
IF IAP_GET_CURRENT_SCORE() > sIAPData.iScoreToShow
RETURN FALSE
ENDIF
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SCORE_TALLY_STARTED)
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SCORE_TALLY_STARTED)
ENDIF
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_ARMOUR_SCORE_ADDED)
IF sIAPData.iEndArmourToShow = 0
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_ARMOUR_SCORE_ADDED)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Total")
IAP_STOP_LOOPING_FRONTEND_SOUND(sIAPData.iTallyLoopSoundId)
ELSE
IF bSkipPressed
IAP_ADD_SCORE(ciIAP_SCORE_PER_ARMOUR_REMAINING * sIAPData.iEndArmourToShow, IAP_SCORE_TYPE_LIVES, INIT_VECTOR_2D(-1, -1))
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Large")
sIAPData.iEndArmourToShow = 0
sIAPData.iScoreToShow = IAP_GET_CURRENT_SCORE()
RETURN FALSE
ENDIF
sIAPData.iEndArmourToShow --
IAP_START_LOOPING_FRONTEND_SOUND("Frontend_Score_Tick_Loop_Small", sIAPData.iTallyLoopSoundId)
IAP_ADD_SCORE(ciIAP_SCORE_PER_ARMOUR_REMAINING, IAP_SCORE_TYPE_ARMOUR, INIT_VECTOR_2D(-1, -1))
ENDIF
RETURN FALSE
ENDIF
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_LIVES_SCORE_ADDED)
IF sIAPData.iEndLivesToShow <= 0
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_LIVES_SCORE_ADDED)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Total")
RETURN FALSE
ELSE
IF bSkipPressed
IAP_ADD_SCORE(ciIAP_SCORE_PER_LIFE_REMAINING * sIAPData.iEndLivesToShow, IAP_SCORE_TYPE_LIVES, INIT_VECTOR_2D(-1, -1))
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Large")
sIAPData.iEndLivesToShow = 0
sIAPData.iScoreToShow = IAP_GET_CURRENT_SCORE()
RETURN FALSE
ENDIF
sIAPData.iEndLivesToShow --
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Large")
IAP_ADD_SCORE(ciIAP_SCORE_PER_LIFE_REMAINING, IAP_SCORE_TYPE_LIVES, INIT_VECTOR_2D(-1, -1))
ENDIF
RETURN FALSE
ENDIF
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_DISTANCE_SCORE_ADDED)
IF sIAPData.iEndDistanceToShow = 0
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_DISTANCE_SCORE_ADDED)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Total")
IAP_STOP_LOOPING_FRONTEND_SOUND(sIAPData.iTallyLoopSoundId)
ELSE
IF bSkipPressed
IAP_ADD_SCORE(ROUND(cfIAP_DISTANCE_CONVERSION * cfIAP_DISTANCE_SCORE_MOD) * sIAPData.iEndDistanceToShow, IAP_SCORE_TYPE_LIVES, INIT_VECTOR_2D(-1, -1))
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Score_Tick_Large")
sIAPData.iEndDistanceToShow = 0
sIAPData.iScoreToShow = IAP_GET_CURRENT_SCORE()
RETURN FALSE
ENDIF
sIAPData.iEndDistanceToShow --
IAP_START_LOOPING_FRONTEND_SOUND("Frontend_Score_Tick_Loop_Small", sIAPData.iTallyLoopSoundId)
IAP_ADD_SCORE(ROUND(cfIAP_DISTANCE_CONVERSION * cfIAP_DISTANCE_SCORE_MOD), IAP_SCORE_TYPE_DISTANCE, INIT_VECTOR_2D(-1, -1))
ENDIF
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
// ------------------------------ ANIMATION ------------------------------
/// PURPOSE:
/// Updates the values used for animating sprite sequences
PROC IAP_UPDATE_ANIM_FRAMES()
sIAPData.iFrameTimeCounter15FPS += ROUND(GET_FRAME_TIME() * 1000)
sIAPData.iUpdateFrames15FPS = FLOOR(sIAPData.iFrameTimeCounter15FPS / 66.0)
sIAPData.iFrameTimeCounter15FPS = sIAPData.iFrameTimeCounter15FPS - ROUND(66.0 * sIAPData.iUpdateFrames15FPS)
sIAPData.iFrameTimeCounter30FPS += ROUND(GET_FRAME_TIME() * 1000)
sIAPData.iUpdateFrames30FPS = FLOOR(sIAPData.iFrameTimeCounter30FPS / 33.0)
sIAPData.iFrameTimeCounter30FPS = sIAPData.iFrameTimeCounter30FPS - ROUND(33.0 * sIAPData.iUpdateFrames30FPS)
ENDPROC
// ------------------------------ ASSET LOADING ------------------------------
FUNC BOOL IAP_HAVE_ALL_ASSETS_LOADED()
IF NOT ARCADE_GAMES_POSTFX_REQUESTING_ASSETS()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading PostFX")
RETURN FALSE
ENDIF
//Texture Dictionaries
REQUEST_STREAMED_TEXTURE_DICT(IAP_GET_PLAYER_TEXTURE_DICT())
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED(IAP_GET_PLAYER_TEXTURE_DICT())
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading ", IAP_GET_PLAYER_TEXTURE_DICT())
RETURN FALSE
ENDIF
REQUEST_STREAMED_TEXTURE_DICT("MPInvPersHud")
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED("MPInvPersHud")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading MPInvPersHud")
RETURN FALSE
ENDIF
REQUEST_STREAMED_TEXTURE_DICT("MPInvPersMessages")
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED("MPInvPersMessages")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading MPInvPersMessages")
RETURN FALSE
ENDIF
REQUEST_STREAMED_TEXTURE_DICT("MPInvPersMessages2")
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED("MPInvPersMessages2")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading MPInvPersMessages2")
RETURN FALSE
ENDIF
REQUEST_STREAMED_TEXTURE_DICT("MpInvPersCommon")
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED("MpInvPersCommon")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading MpInvPersCommon")
RETURN FALSE
ENDIF
//Additional Text
REQUEST_ADDITIONAL_TEXT("IAP", MINIGAME_TEXT_SLOT)
IF NOT HAS_THIS_ADDITIONAL_TEXT_LOADED("IAP", MINIGAME_TEXT_SLOT)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading Additional Text: IAP")
RETURN FALSE
ENDIF
//Audio
IF NOT REQUEST_SCRIPT_AUDIO_BANK("DLC_VINEWOOD/DLC_VW_AM_IP")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_ALL_ASSETS_LOADED - Loading Audio Bank DLC_VINEWOOD/DLC_VW_AM_IP")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
FUNC BOOL IAP_HAVE_CURRENT_STAGE_ASSETS_LOADED()
REQUEST_STREAMED_TEXTURE_DICT(sIAPData.stLoadedStageTextureDictionary)
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED(sIAPData.stLoadedStageTextureDictionary)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_HAVE_CURRENT_STAGE_ASSETS_LOADED - Loading ", sIAPData.stLoadedStageTextureDictionary)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
// ------------------------------ BINK MOVIES ------------------------------
/// PURPOSE:
/// Sets the bink movie asset for the intro video and starts playback
PROC IAP_START_DEGENETRON_INTRO_MOVIE()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_START_DEGENETRON_INTRO_MOVIE - Starting intro movie")
sIAPData.binkDegenIntro = SET_BINK_MOVIE("_1992_DegenatronLogo_720_auto")
PLAY_BINK_MOVIE(sIAPData.binkDegenIntro)
SET_BINK_SHOULD_SKIP(sIAPData.binkDegenIntro, TRUE)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Degenatron_Screen")
ENDPROC
/// PURPOSE:
/// Sets the bink movie asset for the title intro movie and starts playback
PROC IAP_START_TITLE_INTRO_MOVIE_LOOP()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_START_TITLE_INTRO_MOVIE_LOOP - Starting title movie")
sIAPData.binkIntroLoop = SET_BINK_MOVIE("I&P_intro_16x9")
PLAY_BINK_MOVIE(sIAPData.binkIntroLoop)
SET_BINK_SHOULD_SKIP(sIAPData.binkIntroLoop, TRUE)
ENDPROC
/// PURPOSE:
/// Processes stopping and restarting the intro music to keep it in sync with the bink
PROC IAP_PROCESS_TITLE_INTRO_AUDIO()
IF IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STARTED)
IF GET_BINK_MOVIE_TIME(sIAPData.binkIntroLoop) >= 95.0
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_STOP_MUSIC))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] - IAP_PROCESS_TITLE_INTRO_AUDIO - Stopping Intro Music")
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STOPPED)
CLEAR_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STARTED)
ELSE
CLEAR_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STOPPED)
ENDIF
ENDIF
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STARTED)
AND IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STOPPED)
IF GET_BINK_MOVIE_TIME(sIAPData.binkIntroLoop) >= 99.0
OR GET_BINK_MOVIE_TIME(sIAPData.binkIntroLoop) <= 1.0
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_TITLE_SCREEN))
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STARTED)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] - IAP_PROCESS_TITLE_INTRO_AUDIO - Restarting Intro Music")
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Stops the title intro video and releases the bink
PROC IAP_STOP_TITLE_INTRO_MOVIE_LOOP()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_STOP_TITLE_INTRO_MOVIE_LOOP - Stopping title movie")
STOP_BINK_MOVIE(sIAPData.binkIntroLoop)
RELEASE_BINK_MOVIE(sIAPData.binkIntroLoop)
ENDPROC
/// PURPOSE:
/// Sets the bink movie asset for the leaderboard movie and starts playback
PROC IAP_START_LEADERBOARD_MOVIE_LOOP()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_START_LEADERBOARD_MOVIE_LOOP - Starting leaderboard movie")
sIAPData.binkLeaderboard = SET_BINK_MOVIE("I&P_Leaderboard_loop_16x9")
PLAY_BINK_MOVIE(sIAPData.binkLeaderboard)
ENDPROC
/// PURPOSE:
/// Stops the leaderboard video and releases the bink
PROC IAP_STOP_LEADERBOARD_MOVIE_LOOP()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_STOP_LEADERBOARD_MOVIE_LOOP - stopping leaderboard movie")
STOP_BINK_MOVIE(sIAPData.binkLeaderboard)
RELEASE_BINK_MOVIE(sIAPData.binkLeaderboard)
ENDPROC
// ------------------------------ EXPLOSIONS ------------------------------
/// PURPOSE:
/// Triggers an explosion of type at a location
/// PARAMS:
/// vCoords -
/// eType -
PROC IAP_ADD_EXPLOSION_AT_COORDS(VECTOR_2D vCoords, IAP_EXPLOSION eType = IAP_EXPLOSION_MEDIUM)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_ADD_EXPLOSION_AT_COORDS - Adding explosion: ", IAP_DEBUG_GET_IAP_EXPLOSION_AS_STRING(eType), " at (", vCoords.x, ", ", vCoords.y, ")")
sIAPData.sExplosions[sIAPData.iNextExplosionIndex].iAnimFrame = 0
sIAPData.sExplosions[sIAPData.iNextExplosionIndex].vPosition = vCoords
sIAPData.sExplosions[sIAPData.iNextExplosionIndex].eExplosionType = eType
sIAPData.iNextExplosionIndex ++
IF sIAPData.iNextExplosionIndex >= ciIAP_MAX_EXPLOSIONS
sIAPData.iNextExplosionIndex = 0
ENDIF
ENDPROC
/// PURPOSE:
/// Processes the positions of all active explosions
PROC IAP_PROCESS_EXPLOSIONS()
INT i
FOR i = 0 TO ciIAP_MAX_EXPLOSIONS - 1
IF sIAPData.sExplosions[i].iAnimFrame <= -1
RELOOP
ENDIF
sIAPData.sExplosions[i].vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sExplosions[i].vPosition.x, CFIAP_BASE_FOREGROUND_SPEED)
ENDFOR
ENDPROC
// ------------------------------ PROJECTILE PROCESSING ------------------------------
/// PURPOSE:
/// Processes the positions of all player projectiles
PROC IAP_PROCESS_PLAYER_PROJECTILES()
INT i, j
VECTOR_2D v0, v1
RGBA_COLOUR_STRUCT rgba
INIT_RGBA_STRUCT(rgba, 255, 255, 255, 255)
FOR i = 0 TO ciIAP_MAX_PLAYER_PROJECTILES - 1
IF sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_PLASMA
IF sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType].iMaxAnimFrames > 0
sIAPData.sPlayerTank.sProjectileInstances[i].iAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.sProjectileInstances[i].iAnimFrame >= sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType].iMaxAnimFrames
sIAPData.sPlayerTank.sProjectileInstances[i].iAnimFrame = 0
ENDIF
ENDIF
RELOOP
ENDIF
IF sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType].iSpeed
IF sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_HOMING_ROCKET
sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime = -HIGHEST_INT
IF NOT IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION(IAP_GET_HIT_SOUND_FOR_PLAYER_PROJECTILE(sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType), "dlc_vw_am_ip_tank_sounds", sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos)
IAP_ADD_EXPLOSION_AT_COORDS(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos)
ENDIF
ENDIF
RELOOP
ENDIF
FLOAT fAlpha = TO_FLOAT(NATIVE_TO_INT(GET_NETWORK_TIME()) - sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime) / sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType].iSpeed
sIAPData.sPlayerTank.sProjectileInstances[i].vPreviousFramePos = sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos
IF sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_HOMING_ROCKET
FOR j = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF sIAPData.sObjectInstances[j].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[j].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[j].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[j].eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[j].eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[j].eObjectType)].eObjectType = IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
RELOOP
ENDIF
IF sIAPData.sObjectInstances[j].iHealth = 0
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[j].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[j].eObjectType)].vSpriteScale)
RELOOP
ENDIF
VECTOR_2D vPos = sIAPData.sObjectInstances[j].vPosition
IF VECTOR_2D_DIST2(vPos, sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos) < POW(cfIAP_HOMING_ROCKET_RANGE, 2)
sIAPData.sPlayerTank.sProjectileInstances[i].vDirection = vPos
BREAKLOOP
ENDIF
ENDFOR
v1 = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[i].vDirection)
v0 = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos)
sIAPData.sPlayerTank.sProjectileInstances[i].fDesiredRotation = ATAN2(v1.y - v0.y, v1.x - v0.x)
sIAPData.sPlayerTank.sProjectileInstances[i].fDesiredRotation += SIN(TO_FLOAT(NATIVE_TO_INT(GET_NETWORK_TIME()) - sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime)) * 30
IF sIAPData.sPlayerTank.sProjectileInstances[i].fRotation > sIAPData.sPlayerTank.sProjectileInstances[i].fDesiredRotation
sIAPData.sPlayerTank.sProjectileInstances[i].fRotation = CLAMP(sIAPData.sPlayerTank.sProjectileInstances[i].fRotation -@ cfIAP_HOMING_ROCKET_TURN_SPEED, sIAPData.sPlayerTank.sProjectileInstances[i].fDesiredRotation, sIAPData.sPlayerTank.sProjectileInstances[i].fRotation)
ELIF sIAPData.sPlayerTank.sProjectileInstances[i].fDesiredRotation > sIAPData.sPlayerTank.sProjectileInstances[i].fRotation
sIAPData.sPlayerTank.sProjectileInstances[i].fRotation = CLAMP(sIAPData.sPlayerTank.sProjectileInstances[i].fRotation +@ cfIAP_HOMING_ROCKET_TURN_SPEED, sIAPData.sPlayerTank.sProjectileInstances[i].fRotation, sIAPData.sPlayerTank.sProjectileInstances[i].fDesiredRotation)
ENDIF
v0 = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(ROTATE_VECTOR_2D_AROUND_VECTOR_2D(v0, ADD_VECTOR_2D(v0, INIT_VECTOR_2D(cfBASE_SCREEN_WIDTH,0)), sIAPData.sPlayerTank.sProjectileInstances[i].fRotation))
sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos = IAP_MOVE_TOWARDS_VECTOR(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos, v0, cfIAP_HOMING_ROCKET_SPEED)
ELSE
sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos = LERP_VECTOR_2D(sIAPData.sPlayerTank.sProjectileInstances[i].vOrigin, sIAPData.sPlayerTank.sProjectileInstances[i].vDirection, fAlpha)
ENDIF
IF sIAPData.sPlayerTank.sProjectileInstances[i].vDirection.y >= sIAPData.sPlayerTank.sProjectileInstances[i].vOrigin.y
FLOAT fGroundY = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos.x)
IF sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos.y > fGroundY
sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime = -HIGHEST_INT
IF NOT IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION(IAP_GET_HIT_SOUND_FOR_PLAYER_PROJECTILE(sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType), "dlc_vw_am_ip_tank_sounds", sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos)
IAP_ADD_EXPLOSION_AT_COORDS(sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos)
ENDIF
ENDIF
ENDIF
IF sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType].iMaxAnimFrames > 0
sIAPData.sPlayerTank.sProjectileInstances[i].iAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.sProjectileInstances[i].iAnimFrame >= sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType].iMaxAnimFrames
sIAPData.sPlayerTank.sProjectileInstances[i].iAnimFrame = 0
ENDIF
ENDIF
ENDFOR
ENDPROC
/// PURPOSE:
/// Processes the positions of all enemy projectiles
PROC IAP_PROCESS_ENEMY_PROJECTILES()
INT i
FOR i = 0 TO ciIAP_MAX_ENEMY_PROJECTILES - 1
IF sIAPData.sEnemyProjectileInstances[i].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sEnemyProjectileInstances[i].iShotTime + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[i].eProjectileType].iSpeed
RELOOP
ENDIF
IF IAP_IS_NUKE_ACTIVE()
IAP_ADD_EXPLOSION_AT_COORDS(sIAPData.sEnemyProjectileInstances[i].vThisFramePos)
IF sIAPData.sEnemyProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_FALLING_BARREL
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Jet_Bomb_Barrel_Explode", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[i].vThisFramePos)
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Blaster_Fire_Hit", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[i].vThisFramePos)
ENDIF
sIAPData.sEnemyProjectileInstances[i].iShotTime = -HIGHEST_INT
ENDIF
IF sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[i].eProjectileType].iMaxAnimFrames > 0
sIAPData.sEnemyProjectileInstances[i].iAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sEnemyProjectileInstances[i].iAnimFrame >= sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[i].eProjectileType].iMaxAnimFrames
sIAPData.sEnemyProjectileInstances[i].iAnimFrame = 0
ENDIF
ENDIF
FLOAT fAlpha = TO_FLOAT(NATIVE_TO_INT(GET_NETWORK_TIME()) - sIAPData.sEnemyProjectileInstances[i].iShotTime) / sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[i].eProjectileType].iSpeed
sIAPData.sEnemyProjectileInstances[i].vPreviousFramePos = sIAPData.sEnemyProjectileInstances[i].vThisFramePos
sIAPData.sEnemyProjectileInstances[i].vThisFramePos = LERP_VECTOR_2D(sIAPData.sEnemyProjectileInstances[i].vOrigin, sIAPData.sEnemyProjectileInstances[i].vDirection, fAlpha)
IF sIAPData.sEnemyProjectileInstances[i].vDirection.y >= sIAPData.sEnemyProjectileInstances[i].vOrigin.y
FLOAT fGroundY = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sEnemyProjectileInstances[i].vThisFramePos.x)
IF sIAPData.sEnemyProjectileInstances[i].vThisFramePos.y > fGroundY
IAP_ADD_EXPLOSION_AT_COORDS(sIAPData.sEnemyProjectileInstances[i].vThisFramePos)
IF sIAPData.sEnemyProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_FALLING_BARREL
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Jet_Bomb_Barrel_Explode", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[i].vThisFramePos)
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Blaster_Fire_Hit", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[i].vThisFramePos)
ENDIF
sIAPData.sEnemyProjectileInstances[i].iShotTime = -HIGHEST_INT
ENDIF
ENDIF
ENDFOR
ENDPROC
// ------------------------------ OBJECT PROCESSING ------------------------------
/// PURPOSE:
/// Called when an object is no longer on the screen to clean up
PROC IAP_CLEAN_UP_OBJECT(INT iObjectIndex)
IF sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId > -1
RELEASE_SOUND_ID(sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId)
sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId = -1
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId)
sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId = -1
ENDIF
sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
ENDPROC
FUNC BOOL IAP_IS_OBJECT_AN_ANIMAL(INT iObjectIndex)
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_ENEMY_CAMEL
OR sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_ENEMY_BEAR
OR sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_ENEMY_PANDA
OR sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_ENEMY_MOOSE
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Updates an object's health by iHealthChange
PROC IAP_UPDATE_OBJECT_HEALTH(INT iObjectIndex, INT iHealthChange)
IF iHealthChange = 0
EXIT
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth <= 0
//Already dead
EXIT
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_UPDATE_OBJECT_HEALTH - Updating Object ", iObjectIndex, "'s health from ", sIAPData.sObjectInstances[iObjectIndex].iHealth, " Change: ", iHealthChange)
sIAPData.sObjectInstances[iObjectIndex].iHealth = CLAMP_INT(sIAPData.sObjectInstances[iObjectIndex].iHealth + iHealthChange, 0, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iMaxHealth)
sIAPData.sObjectInstances[iObjectIndex].iLastDamagedTime = NATIVE_TO_INT(GET_NETWORK_TIME())
IF sIAPData.sObjectInstances[iObjectIndex].iHealth > 0
EXIT
ENDIF
//Object is dead
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iScoreValue > 0
IAP_ADD_SCORE(sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iScoreValue, IAP_SCORE_TYPE_ENEMY, sIAPData.sObjectInstances[iObjectIndex].vPosition)
IF IAP_IS_OBJECT_AN_ANIMAL(iObjectIndex)
sIAPData.sScoreTracking.iTotalAnimalsKilled ++
ENDIF
ENDIF
IF IAP_DOES_OBJECT_HAVE_DEATH_SOUND(iObjectIndex)
AND sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId != -1
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_OBJECT(IAP_GET_OBJECT_DEATH_SOUND(iObjectIndex), IAP_GET_SOUND_SET_FOR_OBJECT(iObjectIndex), iObjectIndex)
ENDIF
ENDPROC
/// PURPOSE:
/// Processes collecting oil drums by passing them
PROC IAP_PROCESS_OIL_DRUM(INT iObjectIndex)
IF sIAPData.sObjectInstances[iObjectIndex].iLastDamagedTime != -HIGHEST_INT
//Raise the flag
sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition.y = sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition.y +@ cfIAP_FLAG_MAX_Y_SPEED
IF sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition.y > cfIAP_FLAG_MAX_Y_OFFSET
sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition.y = cfIAP_FLAG_MAX_Y_OFFSET
ENDIF
EXIT
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].vPosition.x < sIAPData.sPlayerTank.vPosition.x
sIAPData.sObjectInstances[iObjectIndex].iLastDamagedTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition.y = 0
IAP_ADD_SCORE(sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iScoreValue, IAP_SCORE_TYPE_OIL, sIAPData.sObjectInstances[iObjectIndex].vPosition)
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_OIL_DRUM_NO_SFX) = 0
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_OBJECT("Tank_Raise_Flag", "dlc_vw_am_ip_tank_sounds", iObjectIndex)
ENDIF
IF sIAPData.eCurrentState = IAP_CLIENT_STATE_RUNNING
AND sIAPData.iNextOilToSpawn < 1
IF sIAPData.fStageSpeedMod < cfIAP_MAX_STAGE_SPEED_MOD
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_SPD_UP")
ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Player_Oil_Collect")
sIAPData.fStageSpeedMod += IAP_GET_SPEED_BOOST_FROM_OIL_TYPE(sIAPData.sObjectInstances[iObjectIndex].eObjectType)
IF sIAPData.fStageSpeedMod > cfIAP_MAX_STAGE_SPEED_MOD
sIAPData.fStageSpeedMod = cfIAP_MAX_STAGE_SPEED_MOD
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Returns the distance the next procedurally generated object will spawn
FUNC FLOAT GET_IAP_NEXT_SPAWN_OFFSET()
RETURN GET_RANDOM_FLOAT_IN_RANGE(sIAPData.sRandomGeneration.fMinDistBetweenSpawns, sIAPData.sRandomGeneration.fMaxDistBetweenSpawns)
ENDFUNC
/// PURPOSE:
/// Returns the next procedurally generated object type to spawn
FUNC IAP_OBJECT GET_IAP_OBJECT_TO_SPAWN()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] GET_IAP_OBJECT_TO_SPAWN - Finding object to spawn at ", sIAPData.sRandomGeneration.fNextSpawnDistance)
IAP_OBJECT eValidTypes[COUNT_OF(IAP_OBJECT)]
INT i, j, iValidCount, iInvalidGroupBS
FOR i = 0 TO ciIAP_RANDOM_GENERATION_OBJECT_GROUP_MAX - 1
FOR j = 0 TO ciIAP_RANDOM_GENERATION_OBJECT_GROUP_MAX - 1
//CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] GET_IAP_OBJECT_TO_SPAWN - Checking Groups: ", i, ", ", j, "Min Dist = ", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[i][j])
IF sIAPData.sRandomGeneration.fNextSpawnDistance - sIAPData.sRandomGeneration.fLastSpawnedFromGroup[i] < sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[i][j]
//CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] GET_IAP_OBJECT_TO_SPAWN - Spawn group INVALID - Dist = ", sIAPData.sRandomGeneration.fNextSpawnDistance - sIAPData.sRandomGeneration.fLastSpawnedFromGroup[i])
SET_BIT(iInvalidGroupBS, j)
ENDIF
//CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] GET_IAP_OBJECT_TO_SPAWN - Spawn group OK - Dist = ", sIAPData.sRandomGeneration.fNextSpawnDistance - sIAPData.sRandomGeneration.fLastSpawnedFromGroup[i])
ENDFOR
ENDFOR
FOR i = 0 TO COUNT_OF(IAP_OBJECT) - 1
IF NOT IS_BIT_SET(sIAPData.sObjectData[i].iValidStagesBS, ENUM_TO_INT(sIAPData.eCurrentStage))
RELOOP
ENDIF
IF NOT IS_BIT_SET(iInvalidGroupBS, sIAPData.sObjectData[i].iRandomGenerationObjectGroup)
eValidTypes[iValidCount] = INT_TO_ENUM(IAP_OBJECT, i)
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bRandomPickupsOnly
IF sIAPData.sObjectData[ENUM_TO_INT(eValidTypes[iValidCount])].eObjectType = IAP_OBJECT_TYPE_PICKUP
eValidTypes[iValidCount] = IAP_OBJECT_PICKUP_RANDOM
ENDIF
ENDIF
#ENDIF
iValidCount++
ENDIF
ENDFOR
IF iValidCount = 0
sIAPData.sRandomGeneration.fNextSpawnDistance += GET_IAP_NEXT_SPAWN_OFFSET()
RETURN IAP_OBJECT_NONE
ENDIF
IAP_OBJECT eTypeToReturn = INT_TO_ENUM(IAP_OBJECT, eValidTypes[GET_RANDOM_INT_IN_RANGE(0, iValidCount)])
sIAPData.sRandomGeneration.fLastSpawnedFromGroup[sIAPData.sObjectData[ENUM_TO_INT(eTypeToReturn)].iRandomGenerationObjectGroup] = sIAPData.sRandomGeneration.fNextSpawnDistance
#IF IS_DEBUG_BUILD
sIAPData.sRandomGeneration.iNumSpawnedFromGroup[sIAPData.sObjectData[ENUM_TO_INT(eTypeToReturn)].iRandomGenerationObjectGroup] ++
#ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] GET_IAP_OBJECT_TO_SPAWN - Spawning Object: ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(eTypeToReturn))
RETURN eTypeToReturn
ENDFUNC
/// PURPOSE:
/// Converts an object to another if if is not valid to spawn now
PROC IAP_CONVERT_OBJECT_IF_NOT_VALID_NOW(IAP_OBJECT &eObjectType)
IF eObjectType = IAP_OBJECT_PICKUP_TRIPLE
AND sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_DEFAULT
eObjectType = IAP_OBJECT_PICKUP_SCORE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CONVERT_OBJECT_IF_NOT_VALID_NOW - Converting to score pickup")
ENDIF
ENDPROC
/// PURPOSE:
/// Sets up the object instance with the values for the object type spawning
PROC IAP_INITIALISE_SPAWNED_OBJECT(INT iObjectIndex, IAP_OBJECT eObjectType, INT iFlags, FLOAT fSpawnDistance)
sIAPData.sObjectInstances[iObjectIndex].eObjectType = eObjectType
sIAPData.sObjectInstances[iObjectIndex].iFlags = iFlags
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame = 0
IF sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId)
sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId = -1
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId)
sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId = -1
ENDIF
sIAPData.sObjectInstances[iObjectIndex].iLastDamagedTime = -HIGHEST_INT
sIAPData.sObjectInstances[iObjectIndex].iHealth = sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].iMaxHealth
FLOAT fDistanceOffset = (fSpawnDistance * cfIAP_DISTANCE_CONVERSION) - sIAPData.fDistanceTravelled
FLOAT fXOffset = fDistanceOffset * ((cfIAP_BASE_FOREGROUND_SPEED * sIAPData.fStageSpeedMod) / (sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].fBaseScrollSpeed * sIAPData.fStageSpeedMod))
sIAPData.sObjectInstances[iObjectIndex].vPosition = INIT_VECTOR_2D(1.0 - fXOffset, sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].fBaseYOffset)
#IF IS_DEBUG_BUILD
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_SPAWNED_OBJECT - Distance between objects: ", sIAPData.fDistanceTravelled - fXOffset - sIAPData.sDebugStruct.fLastObjectSpawned)
sIAPData.sDebugStruct.fLastObjectSpawned = sIAPData.fDistanceTravelled - fXOffset
#ENDIF
//Dont add Y offset to Pitfalls, Ledges, Jets or Drones
IF sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType != IAP_OBJECT_TYPE_PITFALL
AND sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType != IAP_OBJECT_TYPE_LEDGE
AND sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType != IAP_OBJECT_TYPE_JET
AND sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType != IAP_OBJECT_TYPE_DRONE
sIAPData.sObjectInstances[iObjectIndex].vPosition.y += IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sObjectInstances[iObjectIndex].vPosition.x)
ENDIF
//Y offset for falling pickups
IF sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
FLOAT fYOffset = fDistanceOffset * (cfIAP_PICKUP_FALL_SPEED)
sIAPData.sObjectInstances[iObjectIndex].vPosition.y -= (cfIAP_PICKUP_SPAWN_Y - fYOffset)
sIAPData.sObjectInstances[iObjectIndex].eState = IAP_OBJECT_STATE_FALLING
ENDIF
//Pitfall and ledge linked objects
IF sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
sIAPData.sParallax.iActiveForegroundSpriteIndexes[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] = ciIAP_PARALLAX_PITFALL
sIAPData.sParallax.iLinkedObjectIndexes[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] = iObjectIndex
sIAPData.sObjectInstances[iObjectIndex].vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fForegroundPosX[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] + ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2), -cfIAP_BASE_FOREGROUND_SPEED)
ELIF sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
sIAPData.sParallax.iActiveForegroundSpriteIndexes[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] = ciIAP_PARALLAX_RAISED_LEDGE
sIAPData.sParallax.iLinkedObjectIndexes[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] = iObjectIndex
sIAPData.sObjectInstances[iObjectIndex].vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fForegroundPosX[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] + ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2), -cfIAP_BASE_FOREGROUND_SPEED)
ENDIF
//Oil drums
IF sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
IF (iFlags & ciIAP_OBJECT_FLAG_OIL_DRUM_RAISED) != 0
sIAPData.sObjectInstances[iObjectIndex].vPosition.y -= sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].vSpriteScale.y / 2
ENDIF
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_SPAWNED_OBJECT - fDistanceOffset: ", fDistanceOffset, " fXOffset: ", fXOffset, " start pos: ", sIAPData.sObjectInstances[sIAPData.iNextObjectIndex].vPosition.x, ", ", sIAPData.sObjectInstances[sIAPData.iNextObjectIndex].vPosition.y)
//Offset time by the distance offset
sIAPData.sObjectInstances[iObjectIndex].iSpawnTime = NATIVE_TO_INT(GET_NETWORK_TIME_ACCURATE())
ENDPROC
/// PURPOSE:
/// Spawns the next object
/// Returns true is successful
FUNC BOOL IAP_SPAWN_OBJECT(IAP_OBJECT eObjectType, FLOAT fSpawnDistance)
IF sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
OR sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] = ciIAP_PARALLAX_PITFALL
OR sIAPData.sParallax.iActiveForegroundSpriteIndexes[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] = ciIAP_PARALLAX_RAISED_LEDGE
OR NOT IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(INIT_VECTOR_2D(sIAPData.sParallax.fForegroundPosX[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] + ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2), sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].fBaseYOffset), sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].vSpriteScale)
//WAIT
RETURN FALSE
ELSE
IF sIAPData.sRandomGeneration.fNextSpawnDistance > -1
AND eObjectType != IAP_OBJECT_CRASHED_TANK
sIAPData.sRandomGeneration.fNextSpawnDistance += ((sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) - sIAPData.sRandomGeneration.fNextSpawnDistance) + ((sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].vSpriteScale.x / 2) / cfIAP_DISTANCE_CONVERSION) + ((1.0 - sIAPData.sParallax.fForegroundPosX[sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1] + ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2)) / -cfIAP_DISTANCE_CONVERSION)
sIAPData.sRandomGeneration.fLastSpawnedFromGroup[sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].iRandomGenerationObjectGroup] = sIAPData.sRandomGeneration.fNextSpawnDistance
ENDIF
ENDIF
ENDIF
IF NOT IAP_IS_NUKE_ACTIVE()
OR IAP_IS_OBJECT_TYPE_NUKE_PROOF(sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].eObjectType)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SPAWN_OBJECT - Spawning object type: ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(eObjectType), " at distance: ", fSpawnDistance)
IAP_CONVERT_OBJECT_IF_NOT_VALID_NOW(eObjectType)
#IF IS_DEBUG_BUILD
IF sIAPData.sObjectInstances[sIAPData.iNextObjectIndex].eObjectType != IAP_OBJECT_NONE
AND sIAPData.eCurrentStage != IAP_STAGE_MOON
ASSERTLN("[IAP] [JS] IAP_SPAWN_OBJECT - OBJECT ", sIAPData.iNextObjectToSpawn, " IS SPAWNING AT AN ACTIVE OBJECT'S INDEX")
ENDIF
#ENDIF
INT iFlags = 0
IF sIAPData.sCurrentStageData.sObjectSpawningData[sIAPData.iNextObjectToSpawn].eObject != IAP_OBJECT_START_RANDOM_GENERATION
iFlags = sIAPData.sCurrentStageData.sObjectSpawningData[sIAPData.iNextObjectToSpawn].iFlags
ENDIF
IAP_INITIALISE_SPAWNED_OBJECT(sIAPData.iNextObjectIndex, eObjectType, iFlags, fSpawnDistance)
sIAPData.iNextObjectIndex++
IF sIAPData.iNextObjectIndex >= ciIAP_MAX_ACTIVE_OBJECTS
sIAPData.iNextObjectIndex = 0
ENDIF
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SPAWN_OBJECT - Skipping due to nuke ", sIAPData.iNextObjectToSpawn)
#ENDIF
ENDIF
IF NOT IS_LONG_BIT_SET(sIAPData.iSpawnedObjectBitSet, ENUM_TO_INT(eObjectType))
SET_LONG_BIT(sIAPData.iSpawnedObjectBitSet, ENUM_TO_INT(eObjectType))
IF NOT IS_STRING_NULL_OR_EMPTY(sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].stHelpText)
IAP_TRIGGER_OBJECT_HELP_TEXT(sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].stHelpText, sIAPData.sObjectData[ENUM_TO_INT(eObjectType)].iHelpTextTime)
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Processes generating and spawning objects for procedurally generated stages
PROC IAP_PROCESS_RANDOM_STAGE_OBJECT_SPAWNING()
IF sIAPData.sCurrentStageData.fStageDistance != ciIAP_STAGE_INFINITE_LENGTH
AND (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= sIAPData.sCurrentStageData.fStageDistance - 12.5
//Leave room for the barrels
sIAPData.iNextObjectToSpawn++
EXIT
ENDIF
FLOAT fAlpha = (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION)/cfIAP_RANDOM_DISTANCE_TO_END_SPAWN_DIST
IF fAlpha > 1.0
fAlpha = 1.0
ENDIF
sIAPData.sRandomGeneration.fMinDistBetweenSpawns = INTERP_FLOAT(cfIAP_RANDOM_MIN_DIST_BETWEEN_SPAWNS_START, cfIAP_RANDOM_MIN_DIST_BETWEEN_SPAWNS_END, fAlpha, INTERPTYPE_DECEL)
sIAPData.sRandomGeneration.fMaxDistBetweenSpawns = INTERP_FLOAT(cfIAP_RANDOM_MAX_DIST_BETWEEN_SPAWNS_START, cfIAP_RANDOM_MAX_DIST_BETWEEN_SPAWNS_END, fAlpha, INTERPTYPE_DECEL)
IF (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) > sIAPData.sRandomGeneration.fNextSpawnDistance
IAP_OBJECT eObjectType = sIAPData.sRandomGeneration.eNextSpawnType
IF eObjectType = IAP_OBJECT_NONE
IF sIAPData.sRandomGeneration.fNextSpawnDistance < 0
SET_RANDOM_SEED(sIAPData.sCurrentStageData.iRandomSeed)
ELSE
SET_RANDOM_SEED(FLOOR(SIN(sIAPData.sRandomGeneration.fNextSpawnDistance)* sIAPData.sRandomGeneration.fNextSpawnDistance))
ENDIF
sIAPData.sRandomGeneration.fNextSpawnDistance += GET_IAP_NEXT_SPAWN_OFFSET()
sIAPData.sRandomGeneration.eNextSpawnType = GET_IAP_OBJECT_TO_SPAWN()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_PROCESS_RANDOM_STAGE_OBJECT_SPAWNING - Next spawn: object type: ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(sIAPData.sRandomGeneration.eNextSpawnType), " at distance: ", sIAPData.sRandomGeneration.fNextSpawnDistance)
EXIT
ENDIF
IF (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= sIAPData.sRandomGeneration.fNextSpawnDistance
IF IAP_SPAWN_OBJECT(sIAPData.sRandomGeneration.eNextSpawnType, sIAPData.sRandomGeneration.fNextSpawnDistance)
sIAPData.sRandomGeneration.eNextSpawnType = IAP_OBJECT_NONE
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Processes spawning objects
PROC IAP_PROCESS_STAGE_OBJECT_SPAWNING()
IF sIAPData.eCurrentState != IAP_CLIENT_STATE_RUNNING
EXIT
ENDIF
FLOAT fSpawnDistance
IAP_OBJECT eObjectType
IF sIAPData.eCurrentStage = IAP_STAGE_MOON
AND NOT IS_LONG_BIT_SET(sIAPData.iSpawnedObjectBitSet, ENUM_TO_INT(IAP_OBJECT_CRASHED_TANK))
IF sIAPData.iCachedMaxMoonDistance < 1
SET_LONG_BIT(sIAPData.iSpawnedObjectBitSet, ENUM_TO_INT(IAP_OBJECT_CRASHED_TANK))
ELIF (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= sIAPData.iCachedMaxMoonDistance - 1
IAP_SPAWN_OBJECT(IAP_OBJECT_CRASHED_TANK, TO_FLOAT(sIAPData.iCachedMaxMoonDistance))
ENDIF
ENDIF
IF sIAPData.iNextObjectToSpawn >= ciIAP_MAX_SPAWNING_OBJECTS
OR sIAPData.sCurrentStageData.sObjectSpawningData[sIAPData.iNextObjectToSpawn].eObject = IAP_OBJECT_NONE
IF sIAPData.sCurrentStageData.fStageDistance = ciIAP_STAGE_INFINITE_LENGTH
EXIT
ENDIF
IF sIAPData.iNextOilToSpawn >= ciIAP_MAX_END_OIL_OBJECTS
EXIT
ENDIF
eObjectType = sIAPData.sCurrentStageData.sEndOilSpawningData[sIAPData.iNextOilToSpawn].eObject
fSpawnDistance = sIAPData.sCurrentStageData.fStageDistance - sIAPData.sCurrentStageData.sEndOilSpawningData[sIAPData.iNextOilToSpawn].fSpawnDistance
IF (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= sIAPData.sCurrentStageData.fStageDistance - 5.0
#IF IS_DEBUG_BUILD
IF sIAPData.sObjectInstances[sIAPData.iNextOilIndex].eObjectType != IAP_OBJECT_NONE
AND sIAPData.eCurrentStage != IAP_STAGE_MOON
ASSERTLN("[IAP] [JS] IAP_PROCESS_STAGE_OBJECT_SPAWNING - OIL ", sIAPData.iNextOilToSpawn, " IS SPAWNING AT AN ACTIVE OBJECT'S INDEX")
ENDIF
#ENDIF
IAP_INITIALISE_SPAWNED_OBJECT(sIAPData.iNextOilIndex, eObjectType, sIAPData.sCurrentStageData.sEndOilSpawningData[sIAPData.iNextOilToSpawn].iFlags, fSpawnDistance)
sIAPData.iNextOilToSpawn++
sIAPData.iNextOilIndex++
IF sIAPData.iNextOilIndex >= ciIAP_MAX_ACTIVE_OBJECTS
sIAPData.iNextOilIndex = 0
ENDIF
ENDIF
EXIT
ENDIF
IF sIAPData.eCurrentState != IAP_CLIENT_STATE_RUNNING
EXIT
ENDIF
IF sIAPData.sCurrentStageData.sObjectSpawningData[sIAPData.iNextObjectToSpawn].eObject = IAP_OBJECT_START_RANDOM_GENERATION
IAP_PROCESS_RANDOM_STAGE_OBJECT_SPAWNING()
EXIT
ENDIF
eObjectType = sIAPData.sCurrentStageData.sObjectSpawningData[sIAPData.iNextObjectToSpawn].eObject
fSpawnDistance = sIAPData.sCurrentStageData.sObjectSpawningData[sIAPData.iNextObjectToSpawn].fSpawnDistance
IF (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= fSpawnDistance
IF IAP_SPAWN_OBJECT(eObjectType, fSpawnDistance)
sIAPData.iNextObjectToSpawn++
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Processing crumbling pits breaking when in range of the player
PROC PROCESS_CRUMBLING_PITFALL(INT iObjectIndex)
IF sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame += ROUND(sIAPData.iUpdateFrames15FPS / ciIAP_PITFALL_CRUMBLE_TRIGGER_DISTANCE_MOD)
IF sIAPData.sObjectInstances[iObjectIndex].iAnimFrame >= ciIAP_PITFALL_CRUMBLE_ANIM_FRAMES
//Fully crumbled
sIAPData.sObjectInstances[iObjectIndex].iFlags = (sIAPData.sObjectInstances[iObjectIndex].iFlags & (ciIAP_OBJECT_FLAG_PITFALL_CRUMBLING ^ -1))
sIAPData.sObjectInstances[iObjectIndex].iHealth = 1
ENDIF
ELIF sIAPData.sObjectInstances[iObjectIndex].vPosition.x < (sIAPData.sPlayerTank.vPosition.x + (IAP_GET_CURRENT_PITFALL_SCALE()))
sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame = 0
IF sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId != -1
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_OBJECT("Enemy_Hazard_Wall_Collapse", "dlc_vw_am_ip_enemy_sounds", iObjectIndex)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Processes all spawned objects positions
PROC IAP_PROCESS_STAGE_OBJECT_POSITION(INT iObjectIndex)
FLOAT fGroundY
IF sIAPData.sObjectInstances[iObjectIndex].vPosition.x < cfIAP_FACADE_WIDTH - (sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale.x / 2)
IAP_CLEAN_UP_OBJECT(iObjectIndex)
EXIT
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId = -1
OR sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId = -1
IF NOT IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale)
sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId = GET_SOUND_ID()
sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId = GET_SOUND_ID()
IF IAP_DOES_OBJECT_HAVE_SPAWN_SOUND(iObjectIndex)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_OBJECT(IAP_GET_OBJECT_SPAWN_SOUND(iObjectIndex), IAP_GET_SOUND_SET_FOR_OBJECT(iObjectIndex), iObjectIndex)
ENDIF
ENDIF
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
AND (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PITFALL_CRUMBLING) != 0
PROCESS_CRUMBLING_PITFALL(iObjectIndex)
ELSE
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sObjectInstances[iObjectIndex].iHealth > 0
SWITCH sIAPData.sObjectInstances[iObjectIndex].eState
CASE IAP_OBJECT_STATE_DEFAULT
CASE IAP_OBJECT_STATE_FALLING
IF sIAPData.sObjectInstances[iObjectIndex].iAnimFrame >= sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iAnimationFrames
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame = 0
ENDIF
BREAK
CASE IAP_OBJECT_STATE_SHOOTING
IF sIAPData.sObjectInstances[iObjectIndex].iAnimFrame >= sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iShootingAnimationFrames
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame = 0
sIAPData.sObjectInstances[iObjectIndex].eState = IAP_OBJECT_STATE_DEFAULT
ENDIF
BREAK
ENDSWITCH
ELSE
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
IF sIAPData.sObjectInstances[iObjectIndex].iAnimFrame > ciIAP_PICKUP_OPEN_FRAMES
IAP_CLEAN_UP_OBJECT(iObjectIndex)
EXIT
ENDIF
ELSE
IF sIAPData.sObjectInstances[iObjectIndex].iAnimFrame > ciIAP_EXPLOSION_FRAMES
IAP_CLEAN_UP_OBJECT(iObjectIndex)
EXIT
ENDIF
ENDIF
ENDIF
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
IAP_PROCESS_OIL_DRUM(iObjectIndex)
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_DRONE
VECTOR_2D vEndMidpoint
FLOAT fDroneSpeed = sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].fBaseScrollSpeed
IF NATIVE_TO_INT(GET_NETWORK_TIME()) - sIAPData.sObjectInstances[iObjectIndex].iSpawnTime > ciIAP_DRONE_LIFESPAN
OR sIAPData.eCurrentState > IAP_CLIENT_STATE_RUNNING
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_DRONE_BOMB_PLAYER_ON_CLEANUP) != 0
AND sIAPData.eCurrentState = IAP_CLIENT_STATE_RUNNING
//Fly straight into the player
vEndMidpoint = sIAPData.sPlayerTank.vPosition
ELSE
vEndMidpoint.x = -1.0
vEndMidpoint.y = 0.0
ENDIF
fDroneSpeed *= 1.25
ELSE
vEndMidpoint = INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_DRONE_END_OFFSET_X, sIAPData.sPlayerTank.vPosition.y + cfIAP_DRONE_END_OFFSET_Y)
IF vEndMidPoint.y > sIAPData.sCurrentStageData.fBaseY + cfIAP_DRONE_END_OFFSET_Y
vEndMidPoint.y = sIAPData.sCurrentStageData.fBaseY + cfIAP_DRONE_END_OFFSET_Y
ENDIF
ENDIF
VECTOR_2D vEnd
vEnd = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(ADD_VECTOR_2D(vEndMidpoint, INIT_VECTOR_2D(cfIAP_DRONE_END_OFFSET_LENGTH, 0)))
vEndMidpoint = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(vEndMidpoint)
FLOAT fSinNumber
fSinNumber = SIN(((sIAPData.fDistanceTravelled * cfIAP_DRONE_SIN_ANGLE_MOD)) + (iObjectIndex * 100))
FLOAT fAngle
fAngle = cfIAP_DRONE_END_POSITION_ANGLE + (fSinNumber * cfIAP_DRONE_END_POSITION_ANGLE_MOD)
VECTOR_2D vEndRight
vEndRight = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vEndMidpoint, vEnd, 180 + fAngle))
sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition = LERP_VECTOR_2D(ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vEndMidpoint), vEndRight, SIN((sIAPData.fDistanceTravelled * cfIAP_DRONE_SIN_POS_MOD) + (iObjectIndex * 100)))
sIAPData.sObjectInstances[iObjectIndex].vPosition = IAP_MOVE_TOWARDS_VECTOR(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectInstances[iObjectIndex].vDesiredPosition, fDroneSpeed)
IF sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId > -1
IF sIAPData.sObjectInstances[iObjectIndex].iHealth > 0
IAP_PLAY_LOOPING_SOUND_FROM_OBJECT("Enemy_Drone_Loop", iObjectIndex)
ENDIF
ENDIF
EXIT
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
AND sIAPData.sObjectInstances[iObjectIndex].eState = IAP_OBJECT_STATE_FALLING
fGroundY = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sObjectInstances[iObjectIndex].vPosition.x)
IF sIAPData.sObjectInstances[iObjectIndex].vPosition.y < sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].fBaseYOffset + fGroundY
sIAPData.sObjectInstances[iObjectIndex].vPosition.y = sIAPData.sObjectInstances[iObjectIndex].vPosition.y +@ cfIAP_PICKUP_FALL_SPEED
IF sIAPData.sObjectInstances[iObjectIndex].vPosition.y >= sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].fBaseYOffset + fGroundY
sIAPData.sObjectInstances[iObjectIndex].vPosition.y = sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].fBaseYOffset + fGroundY
sIAPData.sObjectInstances[iObjectIndex].eState = IAP_OBJECT_STATE_DEFAULT
IF sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId != -1
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_OBJECT("Powerup_Crate_Land", IAP_GET_SOUND_SET_FOR_OBJECT(iObjectIndex),iObjectIndex)
ENDIF
ENDIF
ENDIF
ENDIF
IF sIAPData.eCurrentState != IAP_CLIENT_STATE_RUNNING
AND sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType != IAP_OBJECT_TYPE_JET
EXIT
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_CRASHED_TANK
fGroundY = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sObjectInstances[iObjectIndex].vPosition.x - (sIAPData.sObjectData[IAP_OBJECT_CRASHED_TANK].vSpriteScale.x / 2))
FLOAT fGroundY2 =IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sObjectInstances[iObjectIndex].vPosition.x + (sIAPData.sObjectData[IAP_OBJECT_CRASHED_TANK].vSpriteScale.x / 2))
IF fGroundY > sIAPData.sCurrentStageData.fBaseY
OR NOT IS_FLOAT_IN_RANGE(fGroundY, fGroundY2 - cfARCADE_MINIGAME_FLOAT_TOLERANCE, fGroundY2 + cfARCADE_MINIGAME_FLOAT_TOLERANCE)
OR NOT IS_FLOAT_IN_RANGE(fGroundY + sIAPData.sObjectData[IAP_OBJECT_CRASHED_TANK].fBaseYOffset, sIAPData.sObjectInstances[iObjectIndex].vPosition.y - cfARCADE_MINIGAME_FLOAT_TOLERANCE, sIAPData.sObjectInstances[iObjectIndex].vPosition.y + cfARCADE_MINIGAME_FLOAT_TOLERANCE)
//Move backwards until safe
sIAPData.sObjectInstances[iObjectIndex].vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sObjectInstances[iObjectIndex].vPosition.x, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].fBaseScrollSpeed)
EXIT
ENDIF
ENDIF
sIAPData.sObjectInstances[iObjectIndex].vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sObjectInstances[iObjectIndex].vPosition.x, -sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].fBaseScrollSpeed)
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_JET
IF sIAPData.sObjectInstances[iObjectIndex].iHealth > 0
IF sIAPData.sObjectInstances[iObjectIndex].iLoopingSoundId > -1
IAP_PLAY_LOOPING_SOUND_FROM_OBJECT("Enemy_Jet_Flyover", iObjectIndex)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Returns the time in ms between shots for this enemy
FUNC INT IAP_GET_ENEMY_PROJECTILE_INTERVAL(INT iObjectIndex)
INT iInterval = sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iShotInterval
//Jets shoot speed needs to scale with stage speed or they get easier
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_JET
iInterval = ROUND(iInterval / sIAPData.fStageSpeedMod)
ENDIF
RETURN iInterval
ENDFUNC
/// PURPOSE:
/// Returns the projectile type for the this enemy
FUNC IAP_PROJECTILE_TYPE IAP_GET_ENEMY_PROJECTILE_TYPE(INT iObjectIndex)
SWITCH sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType
CASE IAP_OBJECT_TYPE_GROUND_ENEMY
CASE IAP_OBJECT_TYPE_DRONE
RETURN IAP_PROJECTILE_TYPE_ENEMY
CASE IAP_OBJECT_TYPE_JET
RETURN IAP_PROJECTILE_TYPE_FALLING_BARREL
ENDSWITCH
RETURN IAP_PROJECTILE_TYPE_NONE
ENDFUNC
/// PURPOSE:
/// Returns the starting anim frame for this enemy's projectiles
FUNC INT IAP_GET_ENEMY_PROJECTILE_START_ANIM_FRAME(INT iObjectIndex)
SWITCH sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType
CASE IAP_OBJECT_TYPE_GROUND_ENEMY
CASE IAP_OBJECT_TYPE_DRONE
RETURN -1
CASE IAP_OBJECT_TYPE_JET
RETURN 0
ENDSWITCH
RETURN HIGHEST_INT
ENDFUNC
/// PURPOSE:
/// Returns the origin and end point for this enemy's projectiles
PROC IAP_GET_SHOT_ORIGIN_AND_END_FOR_ENEMY_PROJECTILE(INT iObjectIndex, VECTOR_2D &vShotOrigin, VECTOR_2D &vShotEnd)
vShotOrigin = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(sIAPData.sObjectInstances[iObjectIndex].vPosition.x + sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vShotOffset.x, sIAPData.sObjectInstances[iObjectIndex].vPosition.y + sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vShotOffset.y))
SWITCH sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType
CASE IAP_OBJECT_TYPE_GROUND_ENEMY
vShotEnd = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(1.0, 0.0))), -180)
BREAK
CASE IAP_OBJECT_TYPE_DRONE
vShotEnd = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(1.0, 0.0))), 135)
BREAK
CASE IAP_OBJECT_TYPE_JET
vShotEnd = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(1.0, 0.0))), 85)
BREAK
ENDSWITCH
vShotOrigin = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vShotOrigin)
vShotEnd = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vShotEnd)
ENDPROC
/// PURPOSE:
/// Returns the rotation for this enemy's projectiles
FUNC FLOAT IAP_GET_ENEMY_PROJECTILE_ROTATION(INT iObjectIndex)
SWITCH sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType
CASE IAP_OBJECT_TYPE_GROUND_ENEMY
CASE IAP_OBJECT_TYPE_JET
RETURN 0.0
CASE IAP_OBJECT_TYPE_DRONE
RETURN -45.0
ENDSWITCH
RETURN 0.0
ENDFUNC
/// PURPOSE:
/// Returns the damage dealt by this enemy's projectiles
FUNC INT IAP_GET_ENEMY_PROJECTILE_DAMAGE(INT iObjectIndex)
RETURN sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iShotDamage
ENDFUNC
/// PURPOSE:
/// Processes firing obejct projectiles
PROC IAP_PROCESS_STAGE_OBJECT_SHOOTING(INT iObjectIndex)
IF sIAPData.eCurrentState != IAP_CLIENT_STATE_RUNNING
EXIT
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth <= 0
EXIT
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale)
EXIT
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iShotInterval = 0
EXIT
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) < sIAPData.sObjectInstances[iObjectIndex].iLastShotTime + IAP_GET_ENEMY_PROJECTILE_INTERVAL(iObjectIndex)
EXIT
ENDIF
VECTOR_2D vShotOrigin, vShotEnd
IAP_GET_SHOT_ORIGIN_AND_END_FOR_ENEMY_PROJECTILE(iObjectIndex, vShotOrigin, vShotEnd)
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(vShotOrigin, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
//Dont fire if the start point is outwith the screen
sIAPData.sObjectInstances[iObjectIndex].iLastShotTime = NATIVE_TO_INT(GET_NETWORK_TIME())
EXIT
ENDIF
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].eProjectileType = IAP_GET_ENEMY_PROJECTILE_TYPE(iObjectIndex)
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].vOrigin = vShotOrigin
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].vDirection = vShotEnd
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].vThisFramePos = vShotOrigin
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].vPreviousFramePos = vShotOrigin
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].fRotation = IAP_GET_ENEMY_PROJECTILE_ROTATION(iObjectIndex)
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].iShotTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].iDamage = IAP_GET_ENEMY_PROJECTILE_DAMAGE(iObjectIndex)
sIAPData.sEnemyProjectileInstances[sIAPData.iCurrentEnemyProjectile].iAnimFrame = IAP_GET_ENEMY_PROJECTILE_START_ANIM_FRAME(iObjectIndex)
sIAPData.iCurrentEnemyProjectile++
IF sIAPData.iCurrentEnemyProjectile >= ciIAP_MAX_ENEMY_PROJECTILES
sIAPData.iCurrentEnemyProjectile = 0
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iShootingAnimationFrames > 0
AND sIAPData.eCurrentState = IAP_CLIENT_STATE_RUNNING
sIAPData.sObjectInstances[iObjectIndex].eState = IAP_OBJECT_STATE_SHOOTING
sIAPData.sObjectInstances[iObjectIndex].iAnimFrame = 0
ENDIF
sIAPData.sObjectInstances[iObjectIndex].iLastShotTime = NATIVE_TO_INT(GET_NETWORK_TIME())
IF IAP_DOES_OBJECT_HAVE_SHOOT_SOUND(iObjectIndex)
AND sIAPData.sObjectInstances[iObjectIndex].iOneShotSoundId > -1
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_OBJECT(IAP_GET_OBJECT_SHOOT_SOUND(iObjectIndex), IAP_GET_SOUND_SET_FOR_OBJECT(iObjectIndex), iObjectIndex)
ENDIF
ENDPROC
/// PURPOSE:
/// Processes the object's state while being nuked
PROC IAP_PROCESS_STAGE_OBJECT_NUKED(INT iObjectIndex)
IF IAP_IS_OBJECT_TYPE_NUKE_PROOF(sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType)
EXIT
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth <= 0
EXIT
ENDIF
IF NOT HAS_NET_TIMER_EXPIRED(sIAPData.tdNukeTimer, ciIAP_PICKUP_NUKE_START_DURATION)
sIAPData.sObjectInstances[iObjectIndex].iLastDamagedTime = NATIVE_TO_INT(GET_NETWORK_TIME())
ELSE
IAP_UPDATE_OBJECT_HEALTH(iObjectIndex, -sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iMaxHealth)
ENDIF
ENDPROC
/// PURPOSE:
/// Main object update loop
PROC IAP_PROCESS_STAGE_OBJECTS()
IAP_PROCESS_STAGE_OBJECT_SPAWNING()
INT iObjectIndex
FOR iObjectIndex = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IAP_PROCESS_STAGE_OBJECT_POSITION(iObjectIndex)
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IF IAP_IS_NUKE_ACTIVE()
IAP_PROCESS_STAGE_OBJECT_NUKED(iObjectIndex)
ELSE
IAP_PROCESS_STAGE_OBJECT_SHOOTING(iObjectIndex)
ENDIF
ENDFOR
ENDPROC
// ------------------------------ PLAYER PROCESSING ------------------------------
/// PURPOSE:
/// Updates the player tank state
PROC IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE eNewState)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SET_PLAYER_TANK_STATE - State changed from ",
IAP_DEBUG_GET_IAP_PLAYER_TANK_STATE_AS_STRING(sIAPData.sPlayerTank.eTankState), " to ", IAP_DEBUG_GET_IAP_PLAYER_TANK_STATE_AS_STRING(eNewState))
sIAPData.sPlayerTank.eTankState = eNewState
ENDPROC
/// PURPOSE:
/// Updates the player turret state
PROC IAP_SET_PLAYER_TURRET_STATE(IAP_PLAYER_TURRET_STATE eNewState)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SET_PLAYER_TURRET_STATE - State changed from ",
IAP_DEBUG_GET_IAP_PLAYER_TURRET_STATE_AS_STRING(sIAPData.sPlayerTank.eTurretState), " to ", IAP_DEBUG_GET_IAP_PLAYER_TURRET_STATE_AS_STRING(eNewState))
sIAPData.sPlayerTank.eTurretState = eNewState
ENDPROC
/// PURPOSE:
/// Updates the player's weapon type
PROC IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON eWeapon)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SET_PLAYER_WEAPON_TYPE - Weapon changed from ",
IAP_DEBUG_GET_IAP_PLAYER_WEAPON_AS_STRING(sIAPData.sPlayerTank.eWeaponType), " to ", IAP_DEBUG_GET_IAP_PLAYER_WEAPON_AS_STRING(eWeapon))
sIAPData.sPlayerTank.eWeaponType = eWeapon
IF eWeapon != IAP_PLAYER_WEAPON_DEFAULT
AND IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_TRIPLE_SHOT_ACTIVE)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SET_PLAYER_WEAPON_TYPE - Triple Fire deactivated")
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_TRIPLE_SHOT_ACTIVE)
ENDIF
ENDPROC
/// PURPOSE:
/// Updates the player's global state
PROC IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE eState)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SET_GLOBAL_PLAYER_STATE - State changed from ",
IAP_DEBUG_GET_CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_STRING(g_sCasinoArcadeInvadeAndPersuadeVars.ePlayerState), " to ", IAP_DEBUG_GET_CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_STRING(eState))
g_sCasinoArcadeInvadeAndPersuadeVars.ePlayerState = eState
ENDPROC
/// PURPOSE:
/// Updates the player's health
PROC IAP_CHANGE_PLAYER_HEALTH(INT iHealthChange)
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bNoDamage
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CHANGE_PLAYER_HEALTH - bNoDamage on!")
EXIT
ENDIF
#ENDIF
IF sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_EXPLODING
OR sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_RESPAWNING
EXIT
ENDIF
IF iHealthChange < 0
IF (sIAPData.sPlayerTank.iLastDamagedTime + ciIAP_PLAYER_DAMAGE_RED_TIME > NATIVE_TO_INT(GET_NETWORK_TIME())
OR sIAPData.sPlayerTank.iRespawnTime + ciIAP_PLAYER_RESPAWN_INVULN_TIME > NATIVE_TO_INT(GET_NETWORK_TIME()))
EXIT
ENDIF
IF IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHIELD_ACTIVE)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CHANGE_PLAYER_HEALTH - Shield deactivated")
CLEAR_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHIELD_ACTIVE)
EXIT
ENDIF
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CHANGE_PLAYER_HEALTH - Current Health = ", sIAPData.sPlayerTank.iHealth, " iHealthChange = ", iHealthChange)
INT iMinHealth = PICK_INT(sIAPData.sPlayerTank.iHealth > 1, 1, 0)
INT iNewHealth = CLAMP_INT(sIAPData.sPlayerTank.iHealth + iHealthChange, iMinHealth, ciIAP_MAX_HEALTH)
sIAPData.sPlayerTank.iDisplayHealth = sIAPData.sPlayerTank.iHealth
sIAPData.sPlayerTank.iHealth = iNewHealth
IF iHealthChange < 0
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bLoseWeaponOnHit
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_DEFAULT
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
ENDIF
#ENDIF
sIAPData.sPlayerTank.vPosition.x -= cfIAP_PLAYER_TANK_KNOCK_BACK_X
IF sIAPData.sPlayerTank.vPosition.x < cfIAP_PLAYER_TANK_MIN_POS_X
sIAPData.sPlayerTank.vPosition.x = cfIAP_PLAYER_TANK_MIN_POS_X
ENDIF
sIAPData.sPlayerTank.iLastDamagedTime = NATIVE_TO_INT(GET_NETWORK_TIME())
ELIF iHealthChange > 0
sIAPData.sPlayerTank.iLastHealedTime = NATIVE_TO_INT(GET_NETWORK_TIME())
ENDIF
IF iNewHealth = 0
sIAPData.sPlayerTank.iLives --
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_EXPLODING)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Destroyed", sIAPData.sPlayerTank.iGeneralSoundId)
IF sIAPData.sPlayerTank.iLives >= 0
#IF IS_DEBUG_BUILD
OR sIAPData.sDebugStruct.bDontFailWhenOutOfLives = TRUE
#ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Player_Death")
ENDIF
sIAPData.sPlayerTank.iLastJumpTime = NATIVE_TO_INT(GET_NETWORK_TIME())
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_CHANGE_PLAYER_HEALTH - New Health = ", sIAPData.sPlayerTank.iHealth)
ENDPROC
/// PURPOSE:
/// Moves the player tank into the play area, returns true when the tank is in the start position
FUNC BOOL IAP_IS_PLAYER_TANK_IN_START_POSITION()
sIAPData.sPlayerTank.vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sPlayerTank.vPosition.x, -cfIAP_BASE_FOREGROUND_SPEED)
IF sIAPData.sPlayerTank.vPosition.x < cfIAP_PLAYER_TANK_BASE_POS_X
RETURN FALSE
ENDIF
sIAPData.sPlayerTank.vPosition.x = cfIAP_PLAYER_TANK_BASE_POS_X
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Moves the player tank out of the play area, returns true when the tank is in the end position
FUNC BOOL IAP_IS_PLAYER_TANK_IN_END_POSITION()
sIAPData.sPlayerTank.vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sPlayerTank.vPosition.x, -cfIAP_BASE_FOREGROUND_SPEED)
IF sIAPData.sPlayerTank.vPosition.x < 1.0
RETURN FALSE
ENDIF
sIAPData.sPlayerTank.vPosition.x = 1.0
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Every frame processing for the player tank's turret
PROC IAP_PROCESS_PLAYER_TURRET_STATE()
SWITCH sIAPData.sPlayerTank.eTurretState
CASE IAP_PLAYER_TURRET_STATE_DEFAULT
IF sIAPData.sPlayerTank.iTankShootAnimFrame != 0
sIAPData.sPlayerTank.iTankShootAnimFrame = 0
ENDIF
BREAK
CASE IAP_PLAYER_TURRET_STATE_SHOOTING
sIAPData.sPlayerTank.iTankShootAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.iTankShootAnimFrame >= ciIAP_TANK_SHOOT_ANIM_FRAMES
sIAPData.sPlayerTank.iTankShootAnimFrame = 0
IAP_SET_PLAYER_TURRET_STATE(IAP_PLAYER_TURRET_STATE_DEFAULT)
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Resets the player tank state for a respawn
PROC IAP_RESPAWN_PLAYER()
IF sIAPData.sPlayerTank.iLives < 0
#IF IS_DEBUG_BUILD
AND sIAPData.sDebugStruct.bDontFailWhenOutOfLives = FALSE
#ENDIF
EXIT
ENDIF
sIAPData.sPlayerTank.vPosition.x = cfIAP_PLAYER_TANK_BASE_POS_X
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_RESPAWN_POS_Y
sIAPData.sPlayerTank.iRespawnTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sPlayerTank.iHealth = ciIAP_MAX_HEALTH
sIAPData.sPlayerTank.iDisplayHealth = 0
sIAPData.sPlayerTank.iPlayerTankBitset = 0
sIAPData.sPlayerTank.iTurretDirection = 0
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_RESPAWNING)
ENDPROC
/// PURPOSE:
/// Every frame processing for the player tank
PROC IAP_PROCESS_PLAYER_TANK_STATE()
INT iTime = NATIVE_TO_INT(GET_NETWORK_TIME())
FLOAT fAlpha
FLOAT fGroundPosAtTarget, fGroundPosAtTarget2
VECTOR_2D vSmokePos = sIAPData.sPlayerTank.vPosition
FLOAT fGroundY = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X)
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X, fGroundY), INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X, sIAPData.sPlayerTank.vPosition.y), sIAPData.sColours.rgbaPlasma)
ENDIF
#ENDIF
IAP_PLAY_TANK_LOOP()
SWITCH sIAPData.sPlayerTank.eTankState
CASE IAP_PLAYER_TANK_STATE_DEFAULT
sIAPData.sPlayerTank.stTankSprite = "tank_drive"
sIAPData.sPlayerTank.iTankBaseAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.iTankBaseAnimFrame >= ciIAP_TANK_BASE_ANIM_FRAMES
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
ENDIF
IF sIAPData.sPlayerTank.vPosition.y < cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
AND (sIAPData.sPlayerTank.iRespawnTime = -HIGHEST_INT OR iTime - sIAPData.sPlayerTank.iRespawnTime > ROUND(ciIAP_PLAYER_TANK_RESPAWN_FALL_TIME_DOWN * 1.5))
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_FALLING)
sIAPData.sPlayerTank.iLastJumpTime = iTime
ELIF sIAPData.sPlayerTank.vPosition.y - (cfIAP_PLAYER_TANK_BASE_POS_Y/2) > fGroundY
//Hit a wall
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Collision", sIAPData.sPlayerTank.iGeneralSoundId)
sIAPData.sPlayerTank.iLives --
sIAPData.sPlayerTank.iHealth = 0
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_DEFAULT
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_EXPLODING)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Destroyed", sIAPData.sPlayerTank.iGeneralSoundId)
IF sIAPData.sPlayerTank.iLives >= 0
#IF IS_DEBUG_BUILD
OR sIAPData.sDebugStruct.bDontFailWhenOutOfLives = TRUE
#ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Player_Death")
ENDIF
sIAPData.sPlayerTank.iLastJumpTime = iTime
EXIT
ENDIF
BREAK
CASE IAP_PLAYER_TANK_STATE_JUMPING
sIAPData.sPlayerTank.stTankSprite = "tank_jump"
sIAPData.sPlayerTank.iTankBaseAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.iTankBaseAnimFrame >= ciIAP_TANK_JUMP_ANIM_FRAMES
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
ENDIF
fAlpha = (TO_FLOAT(iTime - sIAPData.sPlayerTank.iLastJumpTime) / ciIAP_PLAYER_TANK_JUMP_TIME_UP)
IF fAlpha >= 1.0
fAlpha = 1.0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_FALLING)
sIAPData.sPlayerTank.iLastJumpTime = iTime
ENDIF
sIAPData.sPlayerTank.vPosition.y = INTERP_FLOAT(sIAPData.sPlayerTank.fJumpStartY, sIAPData.sPlayerTank.fJumpEndY, fAlpha, INTERPTYPE_DECEL)
IF sIAPData.sPlayerTank.vPosition.y - (cfIAP_PLAYER_TANK_BASE_POS_Y/2) > fGroundY
//Hit a wall
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Collision", sIAPData.sPlayerTank.iGeneralSoundId)
sIAPData.sPlayerTank.iLives --
sIAPData.sPlayerTank.iHealth = 0
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_DEFAULT
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_EXPLODING)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Destroyed", sIAPData.sPlayerTank.iGeneralSoundId)
IF sIAPData.sPlayerTank.iLives >= 0
#IF IS_DEBUG_BUILD
OR sIAPData.sDebugStruct.bDontFailWhenOutOfLives = TRUE
#ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Player_Death")
ENDIF
sIAPData.sPlayerTank.iLastJumpTime = iTime
EXIT
ENDIF
BREAK
CASE IAP_PLAYER_TANK_STATE_FALLING
sIAPData.sPlayerTank.stTankSprite = "tank_jump"
sIAPData.sPlayerTank.iTankBaseAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.iTankBaseAnimFrame >= ciIAP_TANK_JUMP_ANIM_FRAMES
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
ENDIF
IF sIAPData.sPlayerTank.vPosition.y - (cfIAP_PLAYER_TANK_BASE_POS_Y/2) > fGroundY
//Hit a wall
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Collision", sIAPData.sPlayerTank.iGeneralSoundId)
sIAPData.sPlayerTank.iLives --
sIAPData.sPlayerTank.iHealth = 0
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_DEFAULT
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_EXPLODING)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Destroyed", sIAPData.sPlayerTank.iGeneralSoundId)
IF sIAPData.sPlayerTank.iLives >= 0
#IF IS_DEBUG_BUILD
OR sIAPData.sDebugStruct.bDontFailWhenOutOfLives = TRUE
#ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Player_Death")
ENDIF
sIAPData.sPlayerTank.iLastJumpTime = iTime
EXIT
ENDIF
IF sIAPData.sPlayerTank.vPosition.y > sIAPData.sCurrentStageData.fBaseY
//If we are falling down a pit then go with the stage
sIAPData.sPlayerTank.vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sPlayerTank.vPosition.x, cfIAP_BASE_FOREGROUND_SPEED)
ENDIF
sIAPData.sPlayerTank.vPosition.y = sIAPData.sPlayerTank.vPosition.y +@ INTERP_FLOAT(0, cfIAP_PLAYER_TANK_FALL_SPEED, (TO_FLOAT(iTime - sIAPData.sPlayerTank.iLastJumpTime) / ciIAP_PLAYER_TANK_FALL_ACCEL), INTERPTYPE_ACCEL)
IF sIAPData.sPlayerTank.vPosition.y > cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
IF sIAPData.sPlayerTank.vPosition.y > sIAPData.sCurrentStageData.fBaseY
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Collision", sIAPData.sPlayerTank.iGeneralSoundId)
sIAPData.sPlayerTank.iLives --
sIAPData.sPlayerTank.iHealth = 0
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_DEFAULT
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_EXPLODING)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Destroyed", sIAPData.sPlayerTank.iGeneralSoundId)
IF sIAPData.sPlayerTank.iLives >= 0
#IF IS_DEBUG_BUILD
OR sIAPData.sDebugStruct.bDontFailWhenOutOfLives = TRUE
#ENDIF
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Player_Death")
ENDIF
sIAPData.sPlayerTank.iLastJumpTime = iTime
EXIT
ELSE
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_DEFAULT)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Jump_Land", sIAPData.sPlayerTank.iGeneralSoundId)
sIAPData.sPlayerTank.iLastJumpTime = iTime
ENDIF
ENDIF
BREAK
CASE IAP_PLAYER_TANK_STATE_EXPLODING
sIAPData.sPlayerTank.iTankBaseAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.eCurrentState = IAP_CLIENT_STATE_RUNNING
sIAPData.sPlayerTank.vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sPlayerTank.vPosition.x, cfIAP_BASE_FOREGROUND_SPEED)
ENDIF
IF sIAPData.sPlayerTank.vPosition.y < cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
sIAPData.sPlayerTank.vPosition.y = sIAPData.sPlayerTank.vPosition.y +@ INTERP_FLOAT(0, cfIAP_PLAYER_TANK_FALL_SPEED, (TO_FLOAT(iTime - sIAPData.sPlayerTank.iLastJumpTime) / ciIAP_PLAYER_TANK_FALL_ACCEL), INTERPTYPE_ACCEL)
IF sIAPData.sPlayerTank.vPosition.y >= cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
ENDIF
ENDIF
IF sIAPData.sPlayerTank.iTankBaseAnimFrame > ciIAP_TANK_EXPLOSION_ANIM_FRAMES
AND sIAPData.eCurrentState = IAP_CLIENT_STATE_RUNNING
IAP_RESPAWN_PLAYER()
ENDIF
BREAK
CASE IAP_PLAYER_TANK_STATE_RESPAWNING
fAlpha = TO_FLOAT(iTime - sIAPData.sPlayerTank.iRespawnTime) / ciIAP_PLAYER_TANK_RESPAWN_FALL_TIME_DOWN
fGroundPosAtTarget = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X + ((-cfIAP_BASE_FOREGROUND_SPEED * sIAPData.fStageSpeedMod)/1000) * (ciIAP_PLAYER_TANK_RESPAWN_FALL_TIME_DOWN * (1 - fAlpha)), TRUE)
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X + ((-cfIAP_BASE_FOREGROUND_SPEED * sIAPData.fStageSpeedMod)/1000) * (ciIAP_PLAYER_TANK_RESPAWN_FALL_TIME_DOWN * (1 - fAlpha)), fGroundPosAtTarget), INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X, sIAPData.sPlayerTank.vPosition.y), sIAPData.sColours.rgbaHeal)
ENDIF
#ENDIF
IF sIAPData.sPlayerTank.vPosition.y < 0.0
IF fGroundPosAtTarget > sIAPData.sCurrentStageData.fBaseY
sIAPData.sPlayerTank.iRespawnTime = iTime
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_RESPAWN_POS_Y
//Gonna land in a pitfall - wait
EXIT
ELSE
fGroundPosAtTarget2 = IAP_GET_GROUND_Y_AT_X_POS(sIAPData.sPlayerTank.vPosition.x + (cfIAP_PLAYER_TANK_SCALE_X) + ((-cfIAP_BASE_FOREGROUND_SPEED * sIAPData.fStageSpeedMod)/1000) * (ciIAP_PLAYER_TANK_RESPAWN_FALL_TIME_DOWN * (1 - fAlpha)), TRUE)
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + (cfIAP_PLAYER_TANK_SCALE_X / 2) + ((-cfIAP_BASE_FOREGROUND_SPEED * sIAPData.fStageSpeedMod)/1000) * (ciIAP_PLAYER_TANK_RESPAWN_FALL_TIME_DOWN * (1 - fAlpha)), fGroundPosAtTarget2), INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_PLAYER_TANK_GROUND_TEST_OFFSET_X, sIAPData.sPlayerTank.vPosition.y), sIAPData.sColours.rgbaBlack)
ENDIF
#ENDIF
IF NOT IS_FLOAT_IN_RANGE(fGroundPosAtTarget2 - fGroundPosAtTarget, -cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE)
//Gonna land with no time to jump before falling/crashing
sIAPData.sPlayerTank.iRespawnTime = iTime
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_RESPAWN_POS_Y
EXIT
ENDIF
ENDIF
ENDIF
sIAPData.sPlayerTank.stTankSprite = "tank_jump"
sIAPData.sPlayerTank.iTankBaseAnimFrame += sIAPData.iUpdateFrames15FPS
IF sIAPData.sPlayerTank.iTankBaseAnimFrame >= ciIAP_TANK_JUMP_ANIM_FRAMES
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
ENDIF
IF fAlpha >= 1.0
fAlpha = 1.0
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Jump_Land", sIAPData.sPlayerTank.iGeneralSoundId)
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_DEFAULT)
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundY
ELSE
sIAPData.sPlayerTank.vPosition.y = INTERP_FLOAT(cfIAP_PLAYER_TANK_RESPAWN_POS_Y, cfIAP_PLAYER_TANK_BASE_POS_Y + fGroundPosAtTarget, fAlpha, INTERPTYPE_ACCEL)
ENDIF
BREAK
ENDSWITCH
IF sIAPData.sPlayerTank.iHealth = 1
IF iTime > sIAPData.sPlayerTank.iLastSmokeTime + ciIAP_TANK_EXPLOSION_SMOKE_INTERVAL
vSmokePos.x += GET_RANDOM_FLOAT_IN_RANGE(-cfIAP_PLAYER_TANK_SCALE_X/2, cfIAP_PLAYER_TANK_SCALE_X/2)
vSmokePos.y += GET_RANDOM_FLOAT_IN_RANGE(-cfIAP_PLAYER_TANK_SCALE_Y/2, cfIAP_PLAYER_TANK_SCALE_Y/2)
IAP_ADD_EXPLOSION_AT_COORDS(vSmokePos, IAP_EXPLOSION_SMOKE)
sIAPData.sPlayerTank.iLastSmokeTime = iTime
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Rotates the player turret by iRotateDelta turns
/// If IgnoreInterval is false this will only rotate if ciIAP_TURRET_ROTATION_INTERVAL ms have passed since last rotation
PROC IAP_ROTATE_TURRET(INT iRotateDelta, BOOL IgnoreInterval = FALSE, FLOAT fAxisValue = 0.0)
INT iInterval = ciIAP_TURRET_ROTATION_INTERVAL
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
AND (fAxisValue > cfSTICK_THRESHOLD * cfIAP_KEYBOARD_MOUSE_AXIS_THRESHOLD_MOD
OR fAxisValue < -cfSTICK_THRESHOLD * cfIAP_KEYBOARD_MOUSE_AXIS_THRESHOLD_MOD)
iInterval = ciIAP_TURRET_ROTATION_INTERVAL_PC
ENDIF
IF NOT IgnoreInterval
IF NATIVE_TO_INT(GET_NETWORK_TIME()) < sIAPData.sPlayerTank.iTurretLastRotationTime + iInterval
EXIT
ENDIF
ENDIF
IF iRotateDelta = 0
EXIT
ENDIF
sIAPData.sPlayerTank.iLastFrameTurretDirection = sIAPData.sPlayerTank.iTurretDirection
sIAPData.sPlayerTank.iTurretDirection += iRotateDelta
IF sIAPData.sPlayerTank.iTurretDirection > ciIAP_MAX_TURRET_DIRECTIONS - 1
sIAPData.sPlayerTank.iTurretDirection = ciIAP_MAX_TURRET_DIRECTIONS - 1
ELIF sIAPData.sPlayerTank.iTurretDirection < -1
sIAPData.sPlayerTank.iTurretDirection = -1
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Turret_Move", sIAPData.sPlayerTank.iTurretSoundId)
ENDIF
sIAPData.sPlayerTank.iTurretLastRotationTime = NATIVE_TO_INT(GET_NETWORK_TIME())
ENDPROC
/// PURPOSE:
/// Returns the time in ms between shots for the current weapon
FUNC INT IAP_GET_CURRENT_WEAPON_PROJECTILE_INTERVAL()
SWITCH sIAPData.sPlayerTank.eWeaponType
CASE IAP_PLAYER_WEAPON_DEFAULT
IF IAP_IS_TRIPLE_FIRE_ACTIVE()
RETURN (ciIAP_BULLET_SHOOTING_INTERVAL / 3)
ENDIF
RETURN ROUND(ciIAP_BULLET_SHOOTING_INTERVAL * IAP_GET_STAGE_WEAPON_SPEED_MOD())
CASE IAP_PLAYER_WEAPON_FLAMETHROWER
RETURN ROUND(ciIAP_FLAME_SHOOTING_INTERVAL * IAP_GET_STAGE_WEAPON_SPEED_MOD())
CASE IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
RETURN ROUND(ciIAP_HOMING_ROCKET_SHOOTING_INTERVAL * IAP_GET_STAGE_WEAPON_SPEED_MOD())
CASE IAP_PLAYER_WEAPON_PLASMA
RETURN ciIAP_PLASMA_SHOOTING_INTERVAL
ENDSWITCH
RETURN HIGHEST_INT
ENDFUNC
/// PURPOSE:
/// Returns the projectile type for the current weapon
FUNC IAP_PROJECTILE_TYPE IAP_GET_CURRENT_WEAPON_PROJECTILE_TYPE()
SWITCH sIAPData.sPlayerTank.eWeaponType
CASE IAP_PLAYER_WEAPON_DEFAULT
RETURN IAP_PROJECTILE_TYPE_BULLET
CASE IAP_PLAYER_WEAPON_FLAMETHROWER
RETURN IAP_PROJECTILE_TYPE_FLAME
CASE IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
RETURN IAP_PROJECTILE_TYPE_HOMING_ROCKET
CASE IAP_PLAYER_WEAPON_PLASMA
RETURN IAP_PROJECTILE_TYPE_PLASMA
ENDSWITCH
RETURN IAP_PROJECTILE_TYPE_NONE
ENDFUNC
/// PURPOSE:
/// Returns the starting anim frame for the current weapon's projectiles
FUNC INT IAP_GET_CURRENT_WEAPON_START_ANIM_FRAME()
SWITCH sIAPData.sPlayerTank.eWeaponType
CASE IAP_PLAYER_WEAPON_DEFAULT
RETURN -1
CASE IAP_PLAYER_WEAPON_FLAMETHROWER
RETURN GET_RANDOM_INT_IN_RANGE(0, ciIAP_FLAME_PROJECTILE_ANIM_START_MAX_FRAME)
CASE IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
RETURN 0
CASE IAP_PLAYER_WEAPON_PLASMA
IF sIAPData.sPlayerTank.sProjectileInstances[0].iAnimFrame >= sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[0].eProjectileType].iMaxAnimFrames
OR sIAPData.sPlayerTank.sProjectileInstances[0].iAnimFrame < 0
sIAPData.sPlayerTank.sProjectileInstances[0].iAnimFrame = 0
ENDIF
RETURN sIAPData.sPlayerTank.sProjectileInstances[0].iAnimFrame
ENDSWITCH
RETURN HIGHEST_INT
ENDFUNC
/// PURPOSE:
/// Updates vShotEnd if the beam intersects the ground
PROC IAP_CHECK_PLASMA_GROUND_INTERSECTION(VECTOR_2D vShotOrigin, VECTOR_2D &vShotEnd)
IF sIAPData.sPlayerTank.iTurretDirection > 0
//Can't hit the ground
EXIT
ENDIF
IF vShotOrigin.y > IAP_GET_GROUND_Y_AT_X_POS(vShotOrigin.x)
vShotEnd = vShotOrigin
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
EXIT
ENDIF
VECTOR_2D vStart, vEnd, vIntersect
vStart.x = sIAPData.sParallax.fForegroundPosX[0] - (IAP_GET_FOREGROUND_X_SCALE(0)/2)
vStart.y = sIAPData.sCurrentStageData.fBaseY
vEnd = vStart
INT i
FOR i = 0 TO sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
//Pitfall
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_PITFALL
AND (sIAPData.sObjectInstances[sIAPData.sParallax.iLinkedObjectIndexes[i]].iFlags & ciIAP_OBJECT_FLAG_PITFALL_CRUMBLING) = 0
FLOAT fEndBefore = vEnd.x
vEnd.x += IAP_GET_CURRENT_STAGE_PITFALL_GROUND_WIDTH_LEFT()
//Left side ground
IF ARCADE_CABINET_GET_LINE_INTERSECT(vShotOrigin, vShotEnd, vStart, vEnd, vIntersect)
vShotEnd = vIntersect
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
EXIT
ENDIF
//Skip left wall as impossible to hit
//Skip bottom as impossible to hit
//Right Wall
vStart.y = 1.0
vEnd.x += IAP_GET_CURRENT_PITFALL_SCALE() - IAP_GET_CURRENT_STAGE_PITFALL_GROUND_WIDTH_LEFT() - IAP_GET_CURRENT_STAGE_PITFALL_GROUND_WIDTH_RIGHT()
vStart.x = vEnd.x
vEnd.y = sIAPData.sCurrentStageData.fBaseY
IF ARCADE_CABINET_GET_LINE_INTERSECT(vShotOrigin, vShotEnd, vStart, vEnd, vIntersect)
vShotEnd = vIntersect
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
EXIT
ENDIF
vStart = vEnd
vEnd.x = fEndBefore + IAP_GET_CURRENT_PITFALL_SCALE()
vStart.x = vEnd.x - IAP_GET_CURRENT_STAGE_PITFALL_GROUND_WIDTH_RIGHT()
//Right side ground handled next change
RELOOP
ENDIF
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_RAISED_LEDGE
//Check current line
IF ARCADE_CABINET_GET_LINE_INTERSECT(vShotOrigin, vShotEnd, vStart, vEnd, vIntersect)
vShotEnd = vIntersect
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
EXIT
ENDIF
//Check left wall
vStart = vEnd
vEnd.y = (1.0 - cfIAP_FACADE_TOP_HEIGHT) - sIAPData.sObjectData[ENUM_TO_INT(IAP_GET_CURRENT_STAGE_LEDGE_INDEX())].vSpriteScale.y + cfIAP_LEDGE_OFFSET
IF ARCADE_CABINET_GET_LINE_INTERSECT(vShotOrigin, vShotEnd, vStart, vEnd, vIntersect)
vShotEnd = vIntersect
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
EXIT
ENDIF
vStart = vEnd
vEnd.x += IAP_GET_FOREGROUND_X_SCALE(i)
//Check top
IF ARCADE_CABINET_GET_LINE_INTERSECT(vShotOrigin, vShotEnd, vStart, vEnd, vIntersect)
vShotEnd = vIntersect
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
EXIT
ENDIF
//Skip right wall, it cant be hit
vEnd.y = sIAPData.sCurrentStageData.fBaseY
vStart = vEnd
RELOOP
ENDIF
//Normal foreground
vEnd.x += IAP_GET_FOREGROUND_X_SCALE(i)
ENDFOR
IF ARCADE_CABINET_GET_LINE_INTERSECT(vShotOrigin, vShotEnd, vStart, vEnd, vIntersect)
vShotEnd = vIntersect
IAP_PLAY_PLASMA_HIT_AT_POSITION(vShotEnd, 1)
ENDIF
ENDPROC
/// PURPOSE:
/// Returns the origin and end point for the current weapon's projectiles
PROC IAP_GET_SHOT_ORIGIN_AND_END_FOR_CURRENT_WEAPON(VECTOR_2D &vShotOrigin, VECTOR_2D &vShotEnd)
FLOAT fJumpOffset = PICK_FLOAT(IAP_IS_PLAYER_TANK_IN_AIR(), cfIAP_PLAYER_TANK_JUMP_SPRITE_OFFSET_Y, 0.0)
SWITCH sIAPData.sPlayerTank.eWeaponType
CASE IAP_PLAYER_WEAPON_DEFAULT
CASE IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
vShotOrigin = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TURRET_OFFSET_X, sIAPData.sPlayerTank.vPosition.y + cfIAP_TURRET_SPRITE_OFFSET_Y + fJumpOffset))
vShotOrigin = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_TURRET_SPRITE_OFFSET_X, 0))), sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
vShotEnd = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(1.0, 0.0))), sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
BREAK
CASE IAP_PLAYER_WEAPON_FLAMETHROWER
vShotOrigin = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TURRET_OFFSET_X + GET_RANDOM_FLOAT_IN_RANGE(-cfIAP_FLAME_PROJECTILE_ORIGIN_MOD, cfIAP_FLAME_PROJECTILE_ORIGIN_MOD), sIAPData.sPlayerTank.vPosition.y + cfIAP_TURRET_SPRITE_OFFSET_Y + fJumpOffset + GET_RANDOM_FLOAT_IN_RANGE(-cfIAP_FLAME_PROJECTILE_ORIGIN_MOD, cfIAP_FLAME_PROJECTILE_ORIGIN_MOD)))
vShotOrigin = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_TURRET_SPRITE_OFFSET_X, 0))), sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT + GET_RANDOM_INT_IN_RANGE(-ciIAP_FLAME_PROJECTILE_ANGLE_MOD, ciIAP_FLAME_PROJECTILE_ANGLE_MOD))
vShotEnd = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_FLAME_PROJECTILE_RANGE + GET_RANDOM_FLOAT_IN_RANGE(0.0, cfIAP_FLAME_PROJECTILE_ADDITIONAL_RANGE_MAX), 0.0))), sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
BREAK
CASE IAP_PLAYER_WEAPON_PLASMA
vShotOrigin = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TURRET_OFFSET_X, sIAPData.sPlayerTank.vPosition.y + cfIAP_TURRET_SPRITE_OFFSET_Y + fJumpOffset))
vShotOrigin = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_TURRET_SPRITE_OFFSET_X / cfIAP_PLASMA_ORIGIN_POSITION_MOD, 0))), sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
vShotEnd = ROTATE_VECTOR_2D_AROUND_VECTOR_2D(vShotOrigin, ADD_VECTOR_2D(vShotOrigin, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(1.0, 0.0))), sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
BREAK
ENDSWITCH
vShotOrigin = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vShotOrigin)
vShotEnd = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vShotEnd)
//Special Case - stop plasma when it intersects the ground
IF sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_PLASMA
IAP_CHECK_PLASMA_GROUND_INTERSECTION(vShotOrigin, vShotEnd)
ENDIF
ENDPROC
/// PURPOSE:
/// Returns the damage dealt by the current weapon's projectiles
FUNC INT IAP_GET_CURRENT_WEAPON_PROJECTILE_DAMAGE()
SWITCH sIAPData.sPlayerTank.eWeaponType
CASE IAP_PLAYER_WEAPON_DEFAULT
RETURN ciIAP_BULLET_WEAPON_DAMAGE
CASE IAP_PLAYER_WEAPON_FLAMETHROWER
RETURN ciIAP_FLAME_WEAPON_DAMAGE
CASE IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
RETURN ciIAP_HOMING_ROCKET_WEAPON_DAMAGE
CASE IAP_PLAYER_WEAPON_PLASMA
RETURN ciIAP_PLASMA_WEAPON_DAMAGE
ENDSWITCH
RETURN 0
ENDFUNC
/// PURPOSE:
/// Fires a projectile from the player's turret
PROC IAP_SHOOT(BOOL bTapped = FALSE)
IF IAP_IS_PLAYER_WEAPON_SOUND_LOOPING()
IAP_PLAY_TANK_WEAPON_LOOP()
ENDIF
IF NOT bTapped
AND NATIVE_TO_INT(GET_NETWORK_TIME()) < sIAPData.sPlayerTank.iTurretLastShootTime + IAP_GET_CURRENT_WEAPON_PROJECTILE_INTERVAL()
EXIT
ENDIF
IF sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_PLASMA
//Plasma always uses shot 0 for easier chaining
sIAPData.sPlayerTank.iCurrentProjectile = 0
ENDIF
VECTOR_2D vShotOrigin, vShotEnd
IAP_GET_SHOT_ORIGIN_AND_END_FOR_CURRENT_WEAPON(vShotOrigin, vShotEnd)
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].eProjectileType = IAP_GET_CURRENT_WEAPON_PROJECTILE_TYPE()
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].vOrigin = vShotOrigin
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].vDirection = vShotEnd
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].vThisFramePos = vShotOrigin
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].fRotation = sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].iDamage = IAP_GET_CURRENT_WEAPON_PROJECTILE_DAMAGE()
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].iAnimFrame = IAP_GET_CURRENT_WEAPON_START_ANIM_FRAME()
sIAPData.sPlayerTank.sProjectileInstances[sIAPData.sPlayerTank.iCurrentProjectile].iShotTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sPlayerTank.iTurretLastShootTime = NATIVE_TO_INT(GET_NETWORK_TIME())
IF sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_FLAMETHROWER
//Randomise the flamethrower interval for a better effect
sIAPData.sPlayerTank.iTurretLastShootTime += GET_RANDOM_INT_IN_RANGE(-ciIAP_FLAME_SHOT_TIME_MOD , ciIAP_FLAME_SHOT_TIME_MOD)
ENDIF
IAP_SET_PLAYER_TURRET_STATE(IAP_PLAYER_TURRET_STATE_SHOOTING)
IF NOT IAP_IS_PLAYER_WEAPON_SOUND_LOOPING()
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK(IAP_GET_SHOOT_SOUND_FOR_CURRENT_PLAYER_WEAPON(), sIAPData.sPlayerTank.iWeaponSoundId)
ENDIF
sIAPData.sPlayerTank.iCurrentProjectile++
IF sIAPData.sPlayerTank.iCurrentProjectile >= ciIAP_MAX_PLAYER_PROJECTILES
sIAPData.sPlayerTank.iCurrentProjectile = 0
ENDIF
ENDPROC
/// PURPOSE:
/// Triggers a player tank jump
PROC IAP_JUMP()
IF sIAPData.sPlayerTank.eTankState != IAP_PLAYER_TANK_STATE_DEFAULT
EXIT
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) < sIAPData.sPlayerTank.iLastJumpTime + ciIAP_PLAYER_TANK_JUMP_INTERVAL
EXIT
ENDIF
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_JUMPING)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Jump", sIAPData.sPlayerTank.iGeneralSoundId)
sIAPData.sPlayerTank.iLastJumpTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sPlayerTank.fJumpStartY = sIAPData.sPlayerTank.vPosition.y
sIAPData.sPlayerTank.fJumpEndY = sIAPData.sPlayerTank.vPosition.y + cfIAP_PLAYER_TANK_JUMP_HEIGHT
ENDPROC
/// PURPOSE:
/// Processes speeding up and slowing down the player tank
PROC IAP_CHANGE_SPEED(BOOL bSpeedUp)
IF sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_FALLING
AND sIAPData.sPlayerTank.vPosition.y > sIAPData.sCurrentStageData.fBaseY
EXIT
ENDIF
sIAPData.sPlayerTank.iMovementModTime += ROUND(GET_FRAME_TIME() * 1000)
FLOAT fAlpha = TO_FLOAT(sIAPData.sPlayerTank.iMovementModTime) / ciIAP_PLAYER_TANK_SPEED_MOD_TIME
IF fAlpha > 1.0
fAlpha = 1.0
ENDIF
IF IAP_IS_PLAYER_TANK_IN_AIR()
#IF IS_DEBUG_BUILD
AND sIAPData.sDebugStruct.bAccelInAir = FALSE
#ENDIF
fAlpha = 1.0
ENDIF
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bNoAccel
fAlpha = 1.0
ENDIF
#ENDIF
FLOAT fSpeedChange = cfIAP_PLAYER_TANK_MAX_SPEED_MOD * INTERP_FLOAT(0, 1, fAlpha, INTERPTYPE_ACCEL)
IF NOT bSpeedUp
fSpeedChange *= -1.0
ENDIF
sIAPData.sPlayerTank.vPosition.x = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sPlayerTank.vPosition.x, fSpeedChange)
IF sIAPData.sPlayerTank.vPosition.x > cfIAP_PLAYER_TANK_MAX_POS_X
sIAPData.sPlayerTank.vPosition.x = cfIAP_PLAYER_TANK_MAX_POS_X
ELIF sIAPData.sPlayerTank.vPosition.x < cfIAP_PLAYER_TANK_MIN_POS_X
sIAPData.sPlayerTank.vPosition.x = cfIAP_PLAYER_TANK_MIN_POS_X
ENDIF
FLOAT fSoundTankSpeed = (sIAPData.fStageSpeedMod / 10)
IF bSpeedUp
fSoundTankSpeed += CLAMP(fAlpha ,fSoundTankSpeed, 0.9)
ELSE
fSoundTankSpeed -= CLAMP(fAlpha ,fSoundTankSpeed, 0.9)
ENDIF
IF sIAPData.sPlayerTank.iEngineLoopSoundId > -1
AND NOT HAS_SOUND_FINISHED(sIAPData.sPlayerTank.iEngineLoopSoundId)
SET_VARIABLE_ON_SOUND(sIAPData.sPlayerTank.iEngineLoopSoundId, "TankSpeed", fSoundTankSpeed)
ENDIF
ENDPROC
// ------------------------------ INPUT ------------------------------
/// PURPOSE:
/// Returns true if the player has pressed start this frame
FUNC BOOL IAP_HAS_PLAYER_PRESSED_START()
CONTROL_ACTION CA_Start = INPUT_FRONTEND_PAUSE
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_Start = INPUT_FRONTEND_ACCEPT
ENDIF
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_Start)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Returns true if the player has pressed quit this frame
FUNC BOOL IAP_HAS_PLAYER_PRESSED_QUIT()
CONTROL_ACTION CA_Quit = INPUT_SCRIPT_RRIGHT
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_Quit = INPUT_FRONTEND_DELETE
ENDIF
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_Quit)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Returns true if player input should be disabled this frame
FUNC BOOL IS_IAP_INPUT_DISABLED_THIS_FRAME()
IF sIAPData.sCurrentStageData.fStageDistance != ciIAP_STAGE_INFINITE_LENGTH
AND (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= sIAPData.sCurrentStageData.fStageDistance
RETURN TRUE
ENDIF
IF sIAPData.sPlayerTank.iHealth <= 0
RETURN TRUE
ENDIF
IF sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_EXPLODING
RETURN TRUE
ENDIF
IF sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_RESPAWNING
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Processes player input before movement has been applied this frame
PROC IAP_PROCESS_INPUT_PRE_MOVEMENT()
IF IS_IAP_INPUT_DISABLED_THIS_FRAME()
EXIT
ENDIF
CONTROL_ACTION CA_SlowDown = INPUT_SCRIPT_PAD_LEFT
CONTROL_ACTION CA_SpeedUp = INPUT_SCRIPT_PAD_RIGHT
CONTROL_ACTION CA_Jump = INPUT_SCRIPT_RLEFT
CONTROL_ACTION CA_RotateLeft = INPUT_SCRIPT_LB
CONTROL_ACTION CA_RotateRight = INPUT_SCRIPT_RB
CONTROL_ACTION CA_TurretFront = INPUT_SCRIPT_LT
CONTROL_ACTION CA_TurretFrontAlt = MAX_INPUTS
FLOAT fAxisThresholdMod = cfIAP_CONTROLLER_AXIS_THRESHOLD_MOD
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_SlowDown = INPUT_SCRIPT_PAD_LEFT
CA_SpeedUp = INPUT_SCRIPT_PAD_RIGHT
CA_TurretFront = INPUT_CURSOR_CANCEL
CA_TurretFrontAlt = INPUT_FRONTEND_DOWN
CA_RotateLeft = INPUT_FRONTEND_LEFT
CA_RotateRight = INPUT_FRONTEND_RIGHT
CA_Jump = INPUT_FRONTEND_X
fAxisThresholdMod = cfIAP_KEYBOARD_MOUSE_AXIS_THRESHOLD_MOD
ENDIF
FLOAT fLeftStickX = GET_DISABLED_CONTROL_NORMAL(FRONTEND_CONTROL, INPUT_SCRIPT_LEFT_AXIS_X)
//Movement
IF fLeftStickX < -cfSTICK_THRESHOLD * fAxisThresholdMod
OR (CA_SlowDown != MAX_INPUTS AND IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_SlowDown))
IAP_CHANGE_SPEED(FALSE)
ELIF fLeftStickX > cfSTICK_THRESHOLD * fAxisThresholdMod
OR (CA_SpeedUp != MAX_INPUTS AND IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_SpeedUp))
IAP_CHANGE_SPEED(TRUE)
ELIF sIAPData.sPlayerTank.iMovementModTime > 0
sIAPData.sPlayerTank.iMovementModTime = 0
FLOAT fSoundTankSpeed = (sIAPData.fStageSpeedMod / 10)
IF sIAPData.sPlayerTank.iEngineLoopSoundId > -1
AND NOT HAS_SOUND_FINISHED(sIAPData.sPlayerTank.iEngineLoopSoundId)
SET_VARIABLE_ON_SOUND(sIAPData.sPlayerTank.iEngineLoopSoundId, "TankSpeed", fSoundTankSpeed)
ENDIF
ENDIF
//Jumping
IF IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_Jump)
IAP_JUMP()
ENDIF
//Turret Rotation
FLOAT fRightStickX = GET_DISABLED_CONTROL_NORMAL(FRONTEND_CONTROL, INPUT_SCRIPT_RIGHT_AXIS_X)
IF (CA_RotateLeft != MAX_INPUTS AND IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_RotateLeft))
IAP_ROTATE_TURRET(1, TRUE)
ELIF (CA_RotateRight != MAX_INPUTS AND IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_RotateRight))
IAP_ROTATE_TURRET(-1, TRUE)
ELIF (CA_RotateLeft != MAX_INPUTS AND IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_RotateLeft))
OR fRightStickX < -cfSTICK_THRESHOLD * fAxisThresholdMod
IAP_ROTATE_TURRET(1, FALSE, fRightStickX)
ELIF (CA_RotateRight != MAX_INPUTS AND IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_RotateRight))
OR fRightStickX > cfSTICK_THRESHOLD * fAxisThresholdMod
IAP_ROTATE_TURRET(-1, FALSE, fRightStickX)
ENDIF
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_TurretFront)
OR (CA_TurretFrontAlt != MAX_INPUTS AND IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_TurretFrontAlt))
IF sIAPData.sPlayerTank.iTurretDirection != 0
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Turret_Move", sIAPData.sPlayerTank.iTurretSoundId)
ENDIF
sIAPData.sPlayerTank.iTurretDirection = 0
sIAPData.sPlayerTank.iLastFrameTurretDirection = 0 //Skip extra beam processing - too powerful
ENDIF
ENDPROC
/// PURPOSE:
/// Processes player input after movement has been applied this frame
PROC IAP_PROCESS_INPUT_POST_MOVEMENT()
IF IS_IAP_INPUT_DISABLED_THIS_FRAME()
IAP_STOP_TANK_WEAPON_LOOP()
EXIT
ENDIF
CONTROL_ACTION CA_Shoot = INPUT_SCRIPT_RDOWN
CONTROL_ACTION CA_Shoot_Alt = INPUT_SCRIPT_RT
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
CA_Shoot = INPUT_CURSOR_ACCEPT
CA_Shoot_Alt = INPUT_VEH_ATTACK2
ENDIF
//Shooting
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_Shoot)
OR (CA_Shoot_Alt != MAX_INPUTS AND IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, CA_Shoot_Alt))
IAP_SHOOT(sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_DEFAULT)
ELIF IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_Shoot)
OR (CA_Shoot_Alt != MAX_INPUTS AND IS_DISABLED_CONTROL_PRESSED(FRONTEND_CONTROL, CA_Shoot_Alt))
IAP_SHOOT()
ELIF sIAPData.sPlayerTank.iWeaponLoopSoundId > -1
IAP_STOP_TANK_WEAPON_LOOP()
ENDIF
ENDPROC
// ------------------------------ PICKUPS ------------------------------
/// PURPOSE:
/// Returns a valid pickup type for a random pickup's reward
FUNC IAP_OBJECT IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP(INT iObjectIndex)
IAP_OBJECT eValidPickups[ciIAP_PICKUP_MAX]
INT iCount = 0
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_FLAMETHROWER) = 0
AND sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_FLAMETHROWER
eValidPickups[iCount] = IAP_OBJECT_PICKUP_FLAMETHROWER
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_FLAMETHROWER))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_ROCKETS) = 0
AND sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
eValidPickups[iCount] = IAP_OBJECT_PICKUP_ROCKETS
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_ROCKETS))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_HEALTH) = 0
AND sIAPData.sPlayerTank.iHealth < ciIAP_MAX_HEALTH
eValidPickups[iCount] = IAP_OBJECT_PICKUP_HEALTH
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_HEALTH))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_LIFE) = 0
eValidPickups[iCount] = IAP_OBJECT_PICKUP_LIFE
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_LIFE))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_SCORE) = 0
eValidPickups[iCount] = IAP_OBJECT_PICKUP_SCORE
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_SCORE))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_SHIELD) = 0
AND NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHIELD_ACTIVE)
eValidPickups[iCount] = IAP_OBJECT_PICKUP_SHIELD
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_SHIELD))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_ENEMY) = 0
eValidPickups[iCount] = IAP_OBJECT_PICKUP_ENEMY
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_ENEMY))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_PLASMA) = 0
AND sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_PLASMA
eValidPickups[iCount] = IAP_OBJECT_PICKUP_PLASMA
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_PLASMA))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_TRIPLE) = 0
AND sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_DEFAULT
AND NOT IAP_IS_TRIPLE_FIRE_ACTIVE()
eValidPickups[iCount] = IAP_OBJECT_PICKUP_TRIPLE
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_TRIPLE))
#ENDIF
ENDIF
IF (sIAPData.sObjectInstances[iObjectIndex].iFlags & ciIAP_OBJECT_FLAG_PICKUP_BLOCK_RANDOM_NUKE) = 0
AND NOT IAP_IS_NUKE_ACTIVE()
eValidPickups[iCount] = IAP_OBJECT_PICKUP_NUKE
iCount++
#IF IS_DEBUG_BUILD
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Blocking ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(IAP_OBJECT_PICKUP_NUKE))
#ENDIF
ENDIF
#IF IS_DEBUG_BUILD
IF iCount = 0
ASSERTLN("[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - NO VALID PICKUP TYPES!")
ENDIF
#ENDIF
IAP_OBJECT ePickup = eValidPickups[GET_RANDOM_INT_IN_RANGE(0, iCount)]
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP - Returning ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(ePickup))
RETURN ePickup
ENDFUNC
/// PURPOSE:
/// Sets a pickup as collected and applies it's effect
PROC IAP_COLLECT_PICKUP(INT iObjectIndex, BOOL bFromRandom = FALSE)
SWITCH sIAPData.sObjectInstances[iObjectIndex].eObjectType
CASE IAP_OBJECT_PICKUP_FLAMETHROWER
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_FLAMETHROWER
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_FLAME")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_FLAMETHROWER)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Weapon_Change", sIAPData.sPlayerTank.iGeneralSoundId)
ELSE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_WAO")
IAP_ADD_SCORE(1000, IAP_SCORE_TYPE_PICKUP, INIT_VECTOR_2D(-1,-1))
ENDIF
BREAK
CASE IAP_OBJECT_PICKUP_ROCKETS
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_ROCKET_LAUNCHER
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_ROCKETS")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_ROCKET_LAUNCHER)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Weapon_Change", sIAPData.sPlayerTank.iGeneralSoundId)
ELSE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_WAO")
IAP_ADD_SCORE(1000, IAP_SCORE_TYPE_PICKUP, INIT_VECTOR_2D(-1,-1))
ENDIF
BREAK
CASE IAP_OBJECT_PICKUP_PLASMA
IF sIAPData.sPlayerTank.eWeaponType != IAP_PLAYER_WEAPON_PLASMA
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_PLASMA")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_PLASMA)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Weapon_Change", sIAPData.sPlayerTank.iGeneralSoundId)
ELSE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_WAO")
IAP_ADD_SCORE(1000, IAP_SCORE_TYPE_PICKUP, INIT_VECTOR_2D(-1,-1))
ENDIF
BREAK
CASE IAP_OBJECT_PICKUP_HEALTH
IF sIAPData.sPlayerTank.iHealth = ciIAP_MAX_HEALTH
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_HPO")
sIAPData.sPlayerTank.iLives ++
ELSE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_HP")
IAP_CHANGE_PLAYER_HEALTH(ciIAP_MAX_HEALTH / 5)
ENDIF
BREAK
CASE IAP_OBJECT_PICKUP_LIFE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_1UP")
sIAPData.sPlayerTank.iLives ++
BREAK
CASE IAP_OBJECT_PICKUP_ENEMY
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_ARMOR")
IAP_CHANGE_PLAYER_HEALTH(-ciIAP_MAX_HEALTH / 5)
BREAK
CASE IAP_OBJECT_PICKUP_SCORE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_SCORE")
IAP_ADD_SCORE(ciIAP_PICKUP_SCORE_VALUE, IAP_SCORE_TYPE_PICKUP, INIT_VECTOR_2D(-1,-1))
BREAK
CASE IAP_OBJECT_PICKUP_RANDOM
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION(IAP_GET_PICKUP_COLLECTION_SOUND(sIAPData.sObjectInstances[iObjectIndex].eObjectType), "dlc_vw_am_ip_powerup_sounds", sIAPData.sObjectInstances[iObjectIndex].vPosition)
sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_GET_RANDOM_PICKUP_EFFECT_FOR_PICKUP(iObjectIndex)
IAP_COLLECT_PICKUP(iObjectIndex, TRUE)
EXIT
CASE IAP_OBJECT_PICKUP_SHIELD
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_SHIELD")
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHIELD_ACTIVE)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_COLLECT_PICKUP - Shield activated")
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHIELD_ACTIVE)
ELSE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_SAO")
IAP_ADD_SCORE(1000, IAP_SCORE_TYPE_PICKUP, INIT_VECTOR_2D(-1,-1))
ENDIF
BREAK
CASE IAP_OBJECT_PICKUP_TRIPLE
IF sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_DEFAULT
AND NOT IAP_IS_TRIPLE_FIRE_ACTIVE()
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_TRIPLE")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_COLLECT_PICKUP - Triple Fire activated")
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_TRIPLE_SHOT_ACTIVE)
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Weapon_Change", sIAPData.sPlayerTank.iGeneralSoundId)
ELSE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_WAO")
IAP_ADD_SCORE(1000, IAP_SCORE_TYPE_PICKUP, INIT_VECTOR_2D(-1,-1))
ENDIF
BREAK
CASE IAP_OBJECT_PICKUP_NUKE
IAP_ADD_ABOVE_PLAYER_TEXT("IAP_PU_NUKE")
IAP_NUKE_SCREEN()
BREAK
ENDSWITCH
sIAPData.sScoreTracking.iPickupsCollected ++
sIAPData.sScoreTracking.iTotalPickupsCollected ++
IF sIAPData.sPlayerTank.iLives > ciIAP_STARTING_LIVES_CHEATED
sIAPData.sPlayerTank.iLives = ciIAP_STARTING_LIVES_CHEATED
ENDIF
IF NOT bFromRandom
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION(IAP_GET_PICKUP_COLLECTION_SOUND(sIAPData.sObjectInstances[iObjectIndex].eObjectType), "dlc_vw_am_ip_powerup_sounds", sIAPData.sObjectInstances[iObjectIndex].vPosition)
ENDIF
ENDPROC
// ------------------------------ COLLISION ------------------------------
/// PURPOSE:
/// Returns the the scale of the projectile covering its current and last frame positions for collision
FUNC VECTOR_2D IAP_GET_PROJECTILE_SCALE_THIS_FRAME(VECTOR_2D vThisFramePos, VECTOR_2D vLastFramePos, VECTOR_2D vSpriteScale)
VECTOR_2D vScale
FLOAT fXDist = ABSF(vThisFramePos.x - vLastFramePos.x)
FLOAT fYDist = ABSF(vThisFramePos.y - vLastFramePos.y)
vScale = INIT_VECTOR_2D(fXDist + vSpriteScale.x, fYDist + vSpriteScale.y)
RETURN vScale
ENDFUNC
/// PURPOSE:
/// Main collision processing loop
PROC IAP_PROCESS_COLLISIONS()
#IF IS_DEBUG_BUILD
INT iDebugLoop
RGBA_COLOUR_STRUCT rgba
#ENDIF
FLOAT fCos
FLOAT fSin
//Player Collision
//Tank:
VECTOR_2D vPlayerCorners[4]
vPlayerCorners[0] = INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TANK_COLLISION_BOTTOM_LEFT_X,
sIAPData.sPlayerTank.vPosition.y + cfIAP_TANK_COLLISION_BOTTOM_LEFT_Y)
vPlayerCorners[1] = INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TANK_COLLISION_TOP_LEFT_X,
sIAPData.sPlayerTank.vPosition.y + cfIAP_TANK_COLLISION_TOP_LEFT_Y)
vPlayerCorners[2] = INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TANK_COLLISION_TOP_RIGHT_X,
sIAPData.sPlayerTank.vPosition.y + cfIAP_TANK_COLLISION_TOP_RIGHT_Y)
vPlayerCorners[3] = INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TANK_COLLISION_BOTTOM_RIGHT_X,
sIAPData.sPlayerTank.vPosition.y + cfIAP_TANK_COLLISION_BOTTOM_RIGHT_Y)
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 0, 255, 0, 255)
FOR iDebugLoop = 0 TO 3
INT iNext = iDebugLoop + 1
IF iNext > 3
iNext = 0
ENDIF
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vPlayerCorners[iDebugLoop], vPlayerCorners[iNext], rgba)
ENDFOR
ENDIF
#ENDIF
//Turret:
FLOAT fJumpOffset = 0
IF sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_JUMPING
OR sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_FALLING
OR sIAPData.sPlayerTank.eTankState = IAP_PLAYER_TANK_STATE_RESPAWNING
fJumpOffset = -((cfIAP_PLAYER_TANK_JUMP_SCALE_Y - cfIAP_PLAYER_TANK_SCALE_Y) / 2)
ENDIF
VECTOR_2D vPlayerTurretCorners[3]
VECTOR_2D vTurretCenter = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(sIAPData.sPlayerTank.vPosition.x + cfIAP_TURRET_OFFSET_X, sIAPData.sPlayerTank.vPosition.y + cfIAP_TURRET_SPRITE_OFFSET_Y + fJumpOffset))
vPlayerTurretCorners[0] = ADD_VECTOR_2D(vTurretCenter, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_TURRET_COLLISION_BOTTOM_LEFT_X, cfIAP_TURRET_COLLISION_BOTTOM_LEFT_Y)))
vPlayerTurretCorners[1] = ADD_VECTOR_2D(vTurretCenter, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_TURRET_COLLISION_TOP_LEFT_X, cfIAP_TURRET_COLLISION_TOP_LEFT_Y)))
vPlayerTurretCorners[2] = ADD_VECTOR_2D(vTurretCenter, ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(INIT_VECTOR_2D(cfIAP_TURRET_COLLISION_CENTRE_RIGHT_X, cfIAP_TURRET_COLLISION_CENTRE_RIGHT_Y)))
IF sIAPData.sPlayerTank.iTurretDirection != 0
fSin = SIN(sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
fCos = COS(sIAPData.sPlayerTank.iTurretDirection * cfIAP_TURRET_DIRECTION_INCREMENT)
vPlayerTurretCorners[0] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vTurretCenter, vPlayerTurretCorners[0], fSin, fCos)
vPlayerTurretCorners[1] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vTurretCenter, vPlayerTurretCorners[1], fSin, fCos)
vPlayerTurretCorners[2] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vTurretCenter, vPlayerTurretCorners[2], fSin, fCos)
ENDIF
vPlayerTurretCorners[0] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerTurretCorners[0])
vPlayerTurretCorners[1] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerTurretCorners[1])
vPlayerTurretCorners[2] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerTurretCorners[2])
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 0, 200, 55, 255)
FOR iDebugLoop = 0 TO 2
INT iNext = iDebugLoop + 1
IF iNext > 2
iNext = 0
ENDIF
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vPlayerTurretCorners[iDebugLoop], vPlayerTurretCorners[iNext], rgba)
ENDFOR
ENDIF
#ENDIF
//Player Projectiles:
VECTOR_2D vPlayerProjectileCorners[ciIAP_MAX_PLAYER_PROJECTILES][4]
VECTOR_2D vFlatCurrentPos, vFlatPreviousPos
INT iProjectileIndex = 0
FOR iProjectileIndex = 0 TO ciIAP_MAX_PLAYER_PROJECTILES - 1
IF sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].iShotTime + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType].iSpeed
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
RELOOP
ENDIF
IF sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_PLASMA
RELOOP
ENDIF
VECTOR_2D vCurrentPosPixels = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].vThisFramePos)
VECTOR_2D vPreviousPosPixels = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].vPreviousFramePos)
VECTOR_2D vMidPoint = DIVIDE_VECTOR_2D(ADD_VECTOR_2D(vCurrentPosPixels, vPreviousPosPixels), 2)
IF NOT IS_FLOAT_IN_RANGE(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].fRotation, -cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE)
fSin = SIN(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].fRotation)
fCos = COS(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].fRotation)
vFlatCurrentPos = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vCurrentPosPixels, -fSin, fCos)
vFlatPreviousPos = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vPreviousPosPixels, -fSin, fCos)
ELSE
vFlatCurrentPos = vCurrentPosPixels
vFlatPreviousPos = vPreviousPosPixels
ENDIF
VECTOR_2D vSpriteScale = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(DIVIDE_VECTOR_2D(sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale, 2))
vPlayerProjectileCorners[iProjectileIndex][0].x = vFlatPreviousPos.x - vSpriteScale.x
vPlayerProjectileCorners[iProjectileIndex][1].x = vPlayerProjectileCorners[iProjectileIndex][0].x
vPlayerProjectileCorners[iProjectileIndex][2].x = vFlatCurrentPos.x + vSpriteScale.x
vPlayerProjectileCorners[iProjectileIndex][3].x = vPlayerProjectileCorners[iProjectileIndex][2].x
vPlayerProjectileCorners[iProjectileIndex][0].y = vFlatPreviousPos.y + vSpriteScale.y
vPlayerProjectileCorners[iProjectileIndex][1].y = vFlatCurrentPos.y - vSpriteScale.y
vPlayerProjectileCorners[iProjectileIndex][2].y = vPlayerProjectileCorners[iProjectileIndex][1].y
vPlayerProjectileCorners[iProjectileIndex][3].y = vPlayerProjectileCorners[iProjectileIndex][0].y
IF NOT IS_FLOAT_IN_RANGE(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].fRotation, -cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE)
vPlayerProjectileCorners[iProjectileIndex][0] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vPlayerProjectileCorners[iProjectileIndex][0], fSin, fCos)
vPlayerProjectileCorners[iProjectileIndex][1] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vPlayerProjectileCorners[iProjectileIndex][1], fSin, fCos)
vPlayerProjectileCorners[iProjectileIndex][2] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vPlayerProjectileCorners[iProjectileIndex][2], fSin, fCos)
vPlayerProjectileCorners[iProjectileIndex][3] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vPlayerProjectileCorners[iProjectileIndex][3], fSin, fCos)
ENDIF
vPlayerProjectileCorners[iProjectileIndex][0] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerProjectileCorners[iProjectileIndex][0])
vPlayerProjectileCorners[iProjectileIndex][1] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerProjectileCorners[iProjectileIndex][1])
vPlayerProjectileCorners[iProjectileIndex][2] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerProjectileCorners[iProjectileIndex][2])
vPlayerProjectileCorners[iProjectileIndex][3] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vPlayerProjectileCorners[iProjectileIndex][3])
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 0, 175, 175, 255)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vPlayerProjectileCorners[iProjectileIndex][0], vPlayerProjectileCorners[iProjectileIndex][2], rgba)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vPlayerProjectileCorners[iProjectileIndex][1], vPlayerProjectileCorners[iProjectileIndex][3], rgba)
ENDIF
#ENDIF
ENDFOR
//Enemy Projectiles:
VECTOR_2D vEnemyProjectileCorners[ciIAP_MAX_ENEMY_PROJECTILES][4]
FOR iProjectileIndex = 0 TO ciIAP_MAX_ENEMY_PROJECTILES - 1
IF sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].iSpeed
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
RELOOP
ENDIF
VECTOR_2D vCurrentPosPixels = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
VECTOR_2D vPreviousPosPixels = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vPreviousFramePos)
VECTOR_2D vMidPoint = DIVIDE_VECTOR_2D(ADD_VECTOR_2D(vCurrentPosPixels, vPreviousPosPixels), 2)
IF NOT IS_FLOAT_IN_RANGE(sIAPData.sEnemyProjectileInstances[iProjectileIndex].fRotation, -cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE)
fSin = SIN(sIAPData.sEnemyProjectileInstances[iProjectileIndex].fRotation)
fCos = COS(sIAPData.sEnemyProjectileInstances[iProjectileIndex].fRotation)
vFlatCurrentPos = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vCurrentPosPixels, -fSin, fCos)
vFlatPreviousPos = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vPreviousPosPixels, -fSin, fCos)
ELSE
vFlatCurrentPos = vCurrentPosPixels
vFlatPreviousPos = vPreviousPosPixels
ENDIF
VECTOR_2D vSpriteScale = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(DIVIDE_VECTOR_2D(sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale, 2))
vEnemyProjectileCorners[iProjectileIndex][0].x = vFlatCurrentPos.x - vSpriteScale.x
vEnemyProjectileCorners[iProjectileIndex][1].x = vEnemyProjectileCorners[iProjectileIndex][0].x
vEnemyProjectileCorners[iProjectileIndex][2].x = vFlatPreviousPos.x + vSpriteScale.x
vEnemyProjectileCorners[iProjectileIndex][3].x = vEnemyProjectileCorners[iProjectileIndex][2].x
vEnemyProjectileCorners[iProjectileIndex][0].y = vFlatPreviousPos.y + vSpriteScale.y
vEnemyProjectileCorners[iProjectileIndex][1].y = vFlatCurrentPos.y - vSpriteScale.y
vEnemyProjectileCorners[iProjectileIndex][2].y = vEnemyProjectileCorners[iProjectileIndex][1].y
vEnemyProjectileCorners[iProjectileIndex][3].y = vEnemyProjectileCorners[iProjectileIndex][0].y
IF NOT IS_FLOAT_IN_RANGE(sIAPData.sEnemyProjectileInstances[iProjectileIndex].fRotation, -cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE)
vEnemyProjectileCorners[iProjectileIndex][0] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vEnemyProjectileCorners[iProjectileIndex][0], fSin, fCos)
vEnemyProjectileCorners[iProjectileIndex][1] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vEnemyProjectileCorners[iProjectileIndex][1], fSin, fCos)
vEnemyProjectileCorners[iProjectileIndex][2] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vEnemyProjectileCorners[iProjectileIndex][2], fSin, fCos)
vEnemyProjectileCorners[iProjectileIndex][3] = ROTATE_VECTOR_2D_AROUND_VECTOR_2D_PRECOMPUTE(vMidPoint, vEnemyProjectileCorners[iProjectileIndex][3], fSin, fCos)
ENDIF
vEnemyProjectileCorners[iProjectileIndex][0] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vEnemyProjectileCorners[iProjectileIndex][0])
vEnemyProjectileCorners[iProjectileIndex][1] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vEnemyProjectileCorners[iProjectileIndex][1])
vEnemyProjectileCorners[iProjectileIndex][2] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vEnemyProjectileCorners[iProjectileIndex][2])
vEnemyProjectileCorners[iProjectileIndex][3] = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(vEnemyProjectileCorners[iProjectileIndex][3])
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 175, 0, 175, 255)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vEnemyProjectileCorners[iProjectileIndex][0], vEnemyProjectileCorners[iProjectileIndex][2], rgba)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vEnemyProjectileCorners[iProjectileIndex][1], vEnemyProjectileCorners[iProjectileIndex][3], rgba)
ENDIF
#ENDIF
ENDFOR
//Object Collision
VECTOR_2D vObjectCorners[4]
VECTOR_2D vIntersectionPoint = INIT_VECTOR_2D(-1, -1)
INT iObjectIndex, i, j
FLOAT fDistanceX, fDistanceY
FOR iObjectIndex = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].vPosition.x - (sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale.x / 2) > (1 - cfIAP_FACADE_WIDTH)
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale)
RELOOP
ENDIF
VECTOR_2D vPos = sIAPData.sObjectInstances[iObjectIndex].vPosition
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
vObjectCorners[i] = ADD_VECTOR_2D(vPos, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vCollisionBounds[i])
ENDFOR
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 255, 0, 0, 255)
FOR iDebugLoop = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT iNext = iDebugLoop + 1
IF iNext > 3
iNext = 0
ENDIF
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(vObjectCorners[iDebugLoop], vObjectCorners[iNext], rgba)
ENDFOR
ENDIF
#ENDIF
//Object Vs Player Tank Collision
IF sIAPData.sPlayerTank.iHealth > 0
AND sIAPData.sPlayerTank.eTankState != IAP_PLAYER_TANK_STATE_EXPLODING
fDistanceX = ABSF(vPos.x - sIAPData.sPlayerTank.vPosition.x)
fDistanceY = ABSF(vPos.y - sIAPData.sPlayerTank.vPosition.y)
IF fDistanceX <= FMAX(sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale.x,cfIAP_PLAYER_TANK_SCALE_X)
AND fDistanceY <= FMAX(sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale.y, cfIAP_PLAYER_TANK_SCALE_Y)
BOOL bHit = FALSE
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT iNext = i + 1
IF iNext >= ciIAP_MAX_OBJECT_COLLISION_POINTS
iNext = 0
ENDIF
FOR j = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT jNext = j + 1
IF jNext >= ciIAP_MAX_OBJECT_COLLISION_POINTS
jNext = 0
ENDIF
IF ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerCorners[i], vPlayerCorners[iNext], vObjectCorners[j], vObjectCorners[jNext], vIntersectionPoint)
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
IAP_COLLECT_PICKUP(iObjectIndex)
sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
ELSE
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType != IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
IAP_UPDATE_OBJECT_HEALTH(iObjectIndex, -sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].iMaxHealth)
ENDIF
IF (sIAPData.sPlayerTank.iLastDamagedTime + ciIAP_PLAYER_DAMAGE_RED_TIME < NATIVE_TO_INT(GET_NETWORK_TIME())
AND sIAPData.sPlayerTank.iRespawnTime + ciIAP_PLAYER_RESPAWN_INVULN_TIME < NATIVE_TO_INT(GET_NETWORK_TIME()))
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_TANK("Tank_Collision", sIAPData.sPlayerTank.iGeneralSoundId)
ENDIF
IAP_CHANGE_PLAYER_HEALTH(-ciIAP_DEFAULT_PLAYER_OBJECT_COLLISION_DAMAGE)
ENDIF
bHit = TRUE
BREAKLOOP
ENDIF
ENDFOR
IF bHit
BREAKLOOP
ENDIF
ENDFOR
IF bHit
RELOOP
ENDIF
ENDIF
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
RELOOP
ENDIF
//Object Vs Player Projectile Collision
FOR iProjectileIndex = 0 TO ciIAP_MAX_PLAYER_PROJECTILES - 1
IF sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_PLASMA
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].iShotTime + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType].iSpeed
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
RELOOP
ENDIF
fDistanceX = ABSF(vPos.x - sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].vThisFramePos.x)
fDistanceY = ABSF(vPos.y - sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].vThisFramePos.y)
IF fDistanceX <= sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale.x + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale.x
AND fDistanceY <= sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale.y + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale.y
BOOL bHit = FALSE
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT iNext = i + 1
IF iNext >= ciIAP_MAX_OBJECT_COLLISION_POINTS
iNext = 0
ENDIF
IF ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerProjectileCorners[iProjectileIndex][0], vPlayerProjectileCorners[iProjectileIndex][2], vObjectCorners[i], vObjectCorners[iNext], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerProjectileCorners[iProjectileIndex][1], vPlayerProjectileCorners[iProjectileIndex][3], vObjectCorners[i], vObjectCorners[iNext], vIntersectionPoint)
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType != IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
IAP_UPDATE_OBJECT_HEALTH(iObjectIndex, -sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].iDamage)
ENDIF
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION(IAP_GET_HIT_SOUND_FOR_PLAYER_PROJECTILE(sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].eProjectileType), "dlc_vw_am_ip_tank_sounds", sIAPData.sPlayerTank.sProjectileInstances[i].vThisFramePos)
IAP_ADD_EXPLOSION_AT_COORDS(vIntersectionPoint)
sIAPData.sPlayerTank.sProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
bHit = TRUE
BREAKLOOP
ENDIF
ENDFOR
IF bHit
RELOOP
ENDIF
ENDIF
ENDFOR
ENDFOR
IF sIAPData.sPlayerTank.eWeaponType = IAP_PLAYER_WEAPON_PLASMA
AND sIAPData.sPlayerTank.sProjectileInstances[0].iShotTime != -HIGHEST_INT
AND sIAPData.sPlayerTank.sProjectileInstances[0].eProjectileType = IAP_PROJECTILE_TYPE_PLASMA
AND NATIVE_TO_INT(GET_NETWORK_TIME()) <= sIAPData.sPlayerTank.sProjectileInstances[0].iShotTime + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[0].eProjectileType].iSpeed
INT iHitObjectsBS = 0
INT iClosestObjectIndex = -1
INT iTargetsHit = 0
FLOAT fClosestDist2 = MAX_FLOAT
VECTOR_2D vIntersect = INIT_VECTOR_2D(-1, -1)
FOR iObjectIndex = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale)
RELOOP
ENDIF
VECTOR_2D vPos = sIAPData.sObjectInstances[iObjectIndex].vPosition
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
vObjectCorners[i] = ADD_VECTOR_2D(vPos, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vCollisionBounds[i])
ENDFOR
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT iNext = i + 1
IF iNext >= ciIAP_MAX_OBJECT_COLLISION_POINTS
iNext = 0
ENDIF
IF ARCADE_CABINET_GET_LINE_INTERSECT(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin, sIAPData.sPlayerTank.sProjectileInstances[0].vDirection, vObjectCorners[i], vObjectCorners[iNext], vIntersectionPoint)
FLOAT fDist2 = VECTOR_2D_DIST2(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin, vIntersectionPoint)
IF fDist2 < fClosestDist2
fClosestDist2 = fDist2
iClosestObjectIndex = iObjectIndex
vIntersect = vIntersectionPoint
ENDIF
ENDIF
ENDFOR
ENDFOR
IF iClosestObjectIndex != -1
iTargetsHit++
SET_BIT(iHitObjectsBS, iClosestObjectIndex)
sIAPData.sPlayerTank.sProjectileInstances[0].vDirection = vIntersect
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iClosestObjectIndex].eObjectType)].eObjectType != IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sObjectInstances[iClosestObjectIndex].iLastDamagedTime + (ciIAP_PLASMA_DAMAGE_INTERVAL * IAP_GET_STAGE_WEAPON_SPEED_MOD())
IAP_UPDATE_OBJECT_HEALTH(iClosestObjectIndex, -sIAPData.sPlayerTank.sProjectileInstances[0].iDamage)
ENDIF
VECTOR_2D v0, v1
FOR i = 0 TO ciIAP_PLASMA_BOUNCE_MAX - 1
BOOL bTargetAquired = FALSE
FOR iObjectIndex = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF IS_BIT_SET(iHitObjectsBS, iObjectIndex)
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale)
RELOOP
ENDIF
VECTOR_2D vPos = sIAPData.sObjectInstances[iObjectIndex].vPosition
IF VECTOR_2D_DIST2(sIAPData.sPlayerTank.sProjectileInstances[i].vDirection, vPos) < POW(cfIAP_PLASMA_BOUNCE_MAX_DISTANCE, 2)
SET_BIT(iHitObjectsBS, iObjectIndex)
bTargetAquired = TRUE
iTargetsHit++
v0 = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[i].vDirection)
v1 = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(vPos)
sIAPData.sPlayerTank.sProjectileInstances[i + 1].eProjectileType = IAP_PROJECTILE_TYPE_PLASMA
sIAPData.sPlayerTank.sProjectileInstances[i + 1].vOrigin = sIAPData.sPlayerTank.sProjectileInstances[i].vDirection
sIAPData.sPlayerTank.sProjectileInstances[i + 1].vDirection = vPos
sIAPData.sPlayerTank.sProjectileInstances[i + 1].vThisFramePos = sIAPData.sPlayerTank.sProjectileInstances[i + 1].vOrigin
sIAPData.sPlayerTank.sProjectileInstances[i + 1].fRotation = ATAN2(v1.y - v0.y, v1.x - v0.x)
sIAPData.sPlayerTank.sProjectileInstances[i + 1].iShotTime = NATIVE_TO_INT(GET_NETWORK_TIME())
sIAPData.sPlayerTank.sProjectileInstances[i + 1].iDamage = ciIAP_PLASMA_WEAPON_DAMAGE
sIAPData.sPlayerTank.sProjectileInstances[i + 1].iAnimFrame = IAP_GET_CURRENT_WEAPON_START_ANIM_FRAME()
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sObjectInstances[iObjectIndex].iLastDamagedTime + (ciIAP_PLASMA_DAMAGE_INTERVAL * IAP_GET_STAGE_WEAPON_SPEED_MOD())
IAP_UPDATE_OBJECT_HEALTH(iObjectIndex, -sIAPData.sPlayerTank.sProjectileInstances[0].iDamage)
ENDIF
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 0, 175, 175, 255)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(sIAPData.sPlayerTank.sProjectileInstances[i+1].vOrigin, sIAPData.sPlayerTank.sProjectileInstances[i+1].vDirection, rgba)
ENDIF
#ENDIF
BREAKLOOP
ENDIF
ENDFOR
IF NOT bTargetAquired
BREAKLOOP
ENDIF
ENDFOR
IAP_PLAY_PLASMA_HIT_AT_POSITION(sIAPData.sPlayerTank.sProjectileInstances[0].vDirection, iTargetsHit)
ENDIF
ENDIF
IF sIAPData.sPlayerTank.iLastFrameTurretDirection != sIAPData.sPlayerTank.iTurretDirection
//Fake sweeping plasma
FLOAT fMidRotation = 0.0
IF sIAPData.sPlayerTank.iLastFrameTurretDirection > sIAPData.sPlayerTank.iTurretDirection
fMidRotation = cfIAP_TURRET_DIRECTION_INCREMENT / 2
ELSE
fMidRotation = -cfIAP_TURRET_DIRECTION_INCREMENT/ 2
ENDIF
VECTOR_2D vMidEnd = ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_SCREENSPACE(ROTATE_VECTOR_2D_AROUND_VECTOR_2D(ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin), ARCADE_CABINET_CONVERT_TO_VECTOR_2D_TO_PIXELSPACE(sIAPData.sPlayerTank.sProjectileInstances[0].vDirection), fMidRotation))
iClosestObjectIndex = -1
fClosestDist2 = MAX_FLOAT
FOR iObjectIndex = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF IS_BIT_SET(iHitObjectsBS, iObjectIndex)
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PICKUP
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_PITFALL
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_LEDGE
OR sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].eObjectType = IAP_OBJECT_TYPE_OIL
RELOOP
ENDIF
IF sIAPData.sObjectInstances[iObjectIndex].iHealth = 0
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sObjectInstances[iObjectIndex].vPosition, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vSpriteScale)
RELOOP
ENDIF
VECTOR_2D vPos = sIAPData.sObjectInstances[iObjectIndex].vPosition
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
vObjectCorners[i] = ADD_VECTOR_2D(vPos, sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iObjectIndex].eObjectType)].vCollisionBounds[i])
ENDFOR
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT iNext = i + 1
IF iNext >= ciIAP_MAX_OBJECT_COLLISION_POINTS
iNext = 0
ENDIF
IF ARCADE_CABINET_GET_LINE_INTERSECT(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin, vMidEnd, vObjectCorners[i], vObjectCorners[iNext], vIntersectionPoint)
FLOAT fDist2 = VECTOR_2D_DIST2(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin, vIntersectionPoint)
IF fDist2 < fClosestDist2
fClosestDist2 = fDist2
iClosestObjectIndex = iObjectIndex
vIntersect = vIntersectionPoint
ENDIF
ENDIF
ENDFOR
ENDFOR
IF iClosestObjectIndex != -1
vMidEnd = vIntersect
IF sIAPData.sObjectData[ENUM_TO_INT(sIAPData.sObjectInstances[iClosestObjectIndex].eObjectType)].eObjectType != IAP_OBJECT_TYPE_INDESTRUCTABLE_HAZARD
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sObjectInstances[iClosestObjectIndex].iLastDamagedTime + (ciIAP_PLASMA_DAMAGE_INTERVAL * IAP_GET_STAGE_WEAPON_SPEED_MOD())
IAP_UPDATE_OBJECT_HEALTH(iClosestObjectIndex, -sIAPData.sPlayerTank.sProjectileInstances[0].iDamage)
ENDIF
ENDIF
ENDIF
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 0, 0, 0, 255)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin, vMidEnd, rgba)
ENDIF
#ENDIF
ENDIF
#IF IS_DEBUG_BUILD
IF sIAPData.sDebugStruct.bDrawCollisionDebug
INIT_RGBA_STRUCT(rgba, 0, 175, 175, 255)
DRAW_DEBUG_LINE_2D_FROM_VECTOR_2D(sIAPData.sPlayerTank.sProjectileInstances[0].vOrigin, sIAPData.sPlayerTank.sProjectileInstances[0].vDirection, rgba)
ENDIF
#ENDIF
ENDIF
FOR iProjectileIndex = 0 TO ciIAP_MAX_ENEMY_PROJECTILES - 1
IF sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].iSpeed
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
RELOOP
ENDIF
//Object Projectile Vs Player Tank
fDistanceX = ABSF(sIAPData.sPlayerTank.vPosition.x - sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos.x)
fDistanceY = ABSF(sIAPData.sPlayerTank.vPosition.y - sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos.y)
IF fDistanceX <= cfIAP_PLAYER_TANK_SCALE_X + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale.x
AND fDistanceY <= cfIAP_PLAYER_TANK_SCALE_Y + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale.y
BOOL bHit = FALSE
FOR i = 0 TO ciIAP_MAX_OBJECT_COLLISION_POINTS - 1
INT iNext = i + 1
IF iNext >= ciIAP_MAX_OBJECT_COLLISION_POINTS
iNext = 0
ENDIF
IF ARCADE_CABINET_GET_LINE_INTERSECT(vEnemyProjectileCorners[iProjectileIndex][0], vEnemyProjectileCorners[iProjectileIndex][2], vPlayerCorners[i], vPlayerCorners[iNext], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(vEnemyProjectileCorners[iProjectileIndex][1], vEnemyProjectileCorners[iProjectileIndex][3], vPlayerCorners[i], vPlayerCorners[iNext], vIntersectionPoint)
IAP_CHANGE_PLAYER_HEALTH(-sIAPData.sEnemyProjectileInstances[iProjectileIndex].iDamage)
IAP_ADD_EXPLOSION_AT_COORDS(vIntersectionPoint)
sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
IF sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_FALLING_BARREL
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Jet_Bomb_Barrel_Explode", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Blaster_Fire_Hit", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ENDIF
bHit = TRUE
BREAKLOOP
ENDIF
ENDFOR
IF bHit
RELOOP
ENDIF
ENDIF
//Object Projectile Vs Player Tank Turret
fDistanceX = ABSF(sIAPData.sPlayerTank.vPosition.x + cfIAP_TURRET_OFFSET_X - sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos.x)
fDistanceY = ABSF(sIAPData.sPlayerTank.vPosition.y + cfIAP_TURRET_SPRITE_OFFSET_Y - sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos.y)
IF fDistanceX <= cfIAP_TURRET_SCALE_X + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale.x
AND fDistanceY <= cfIAP_TURRET_SCALE_Y + sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale.y
BOOL bHit = FALSE
FOR i = 0 TO 2
INT iNext = i + 1
IF iNext > 2
iNext = 0
ENDIF
IF ARCADE_CABINET_GET_LINE_INTERSECT(vEnemyProjectileCorners[iProjectileIndex][0], vEnemyProjectileCorners[iProjectileIndex][2], vPlayerTurretCorners[i], vPlayerTurretCorners[iNext], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(vEnemyProjectileCorners[iProjectileIndex][1], vEnemyProjectileCorners[iProjectileIndex][3], vPlayerTurretCorners[i], vPlayerTurretCorners[iNext], vIntersectionPoint)
IAP_CHANGE_PLAYER_HEALTH(-sIAPData.sEnemyProjectileInstances[iProjectileIndex].iDamage)
IAP_ADD_EXPLOSION_AT_COORDS(vIntersectionPoint)
sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
IF sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_FALLING_BARREL
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Jet_Bomb_Barrel_Explode", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Blaster_Fire_Hit", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ENDIF
bHit = TRUE
BREAKLOOP
ENDIF
ENDFOR
IF bHit
RELOOP
ENDIF
ENDIF
//Object Projectile Collision VS Player Projectile
INT iPlayerProjectileIndex = 0
FOR iPlayerProjectileIndex = 0 TO ciIAP_MAX_PLAYER_PROJECTILES - 1
IF sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
IF NATIVE_TO_INT(GET_NETWORK_TIME()) > sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].iShotTime + sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].eProjectileType].iSpeed
RELOOP
ENDIF
IF sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_PLASMA
IF ARCADE_CABINET_GET_LINE_INTERSECT(sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vOrigin, sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vDirection, vEnemyProjectileCorners[iProjectileIndex][0], vEnemyProjectileCorners[iProjectileIndex][2], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vOrigin, sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vDirection, vEnemyProjectileCorners[iProjectileIndex][1], vEnemyProjectileCorners[iProjectileIndex][3], vIntersectionPoint)
sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
IAP_ADD_EXPLOSION_AT_COORDS(vIntersectionPoint)
IF sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_FALLING_BARREL
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Jet_Bomb_Barrel_Explode", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Blaster_Fire_Hit", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ENDIF
BREAKLOOP
ENDIF
RELOOP
ENDIF
IF IAP_IS_RECT_COMPLETELY_OUTSIDE_OF_GAME_AREA(sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vThisFramePos, INIT_VECTOR_2D(cfARCADE_MINIGAME_FLOAT_TOLERANCE, cfARCADE_MINIGAME_FLOAT_TOLERANCE))
RELOOP
ENDIF
fDistanceX = ABSF(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos.x - sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vThisFramePos.x)
fDistanceY = ABSF(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos.y - sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vThisFramePos.y)
VECTOR_2D vPlayerProjectileScale = IAP_GET_PROJECTILE_SCALE_THIS_FRAME(sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vThisFramePos, sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vPreviousFramePos, sIAPData.sProjectileData[sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].eProjectileType].vSpriteScale)
VECTOR_2D vEnemyProjectileScale = IAP_GET_PROJECTILE_SCALE_THIS_FRAME(sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos, sIAPData.sEnemyProjectileInstances[iProjectileIndex].vPreviousFramePos, sIAPData.sProjectileData[sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType].vSpriteScale)
IF fDistanceX <= vPlayerProjectileScale.x
AND fDistanceY <= vPlayerProjectileScale.y
AND fDistanceX <= vEnemyProjectileScale.x
AND fDistanceY <= vEnemyProjectileScale.y
IF ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerProjectileCorners[iPlayerProjectileIndex][0], vPlayerProjectileCorners[iPlayerProjectileIndex][2], vEnemyProjectileCorners[iProjectileIndex][0], vEnemyProjectileCorners[iProjectileIndex][2], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerProjectileCorners[iPlayerProjectileIndex][1], vPlayerProjectileCorners[iPlayerProjectileIndex][3], vEnemyProjectileCorners[iProjectileIndex][1], vEnemyProjectileCorners[iProjectileIndex][3], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerProjectileCorners[iPlayerProjectileIndex][0], vPlayerProjectileCorners[iPlayerProjectileIndex][2], vEnemyProjectileCorners[iProjectileIndex][1], vEnemyProjectileCorners[iProjectileIndex][3], vIntersectionPoint)
OR ARCADE_CABINET_GET_LINE_INTERSECT(vPlayerProjectileCorners[iPlayerProjectileIndex][1], vPlayerProjectileCorners[iPlayerProjectileIndex][3], vEnemyProjectileCorners[iProjectileIndex][0], vEnemyProjectileCorners[iProjectileIndex][2], vIntersectionPoint)
sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].iShotTime = -HIGHEST_INT
sIAPData.sEnemyProjectileInstances[iProjectileIndex].iShotTime = -HIGHEST_INT
IAP_ADD_EXPLOSION_AT_COORDS(vIntersectionPoint)
IF sIAPData.sEnemyProjectileInstances[iProjectileIndex].eProjectileType = IAP_PROJECTILE_TYPE_FALLING_BARREL
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Jet_Bomb_Barrel_Explode", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ELSE
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION("Enemy_Blaster_Fire_Hit", "dlc_vw_am_ip_enemy_sounds", sIAPData.sEnemyProjectileInstances[iProjectileIndex].vThisFramePos)
ENDIF
IAP_PLAY_FIRE_AND_FORGET_SOUND_FROM_POSITION(IAP_GET_HIT_SOUND_FOR_PLAYER_PROJECTILE(sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].eProjectileType), "dlc_vw_am_ip_tank_sounds", sIAPData.sPlayerTank.sProjectileInstances[iPlayerProjectileIndex].vThisFramePos)
BREAKLOOP
ENDIF
ENDIF
ENDFOR
ENDFOR
ENDPROC
// ------------------------------ STAGE SCROLLING ------------------------------
/// PURPOSE:
/// Updates the locations of the stage background sprites
PROC IAP_PROCESS_SCROLLING_STAGE()
INT i
//Background Position
IF sIAPData.eCurrentStage != IAP_STAGE_MOON
sIAPData.sParallax.fBackgroundPosX = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fBackgroundPosX, cfIAP_BASE_BACKGROUND_SPEED)
IF sIAPData.sParallax.fBackgroundPosX < cfIAP_FACADE_WIDTH - (sIAPData.sCurrentStageData.vBackgroundSpriteScale.x/2)
sIAPData.sParallax.fBackgroundPosX += sIAPData.sCurrentStageData.vBackgroundSpriteScale.x
ENDIF
ENDIF
//Midground 1 Position
sIAPData.sParallax.fMidground1PosX = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fMidground1PosX, CFIAP_BASE_MIDGROUND1_SPEED)
IF sIAPData.sParallax.fMidground1PosX < cfIAP_FACADE_WIDTH - (sIAPData.sCurrentStageData.vMidground1SpriteScale.x/2)
sIAPData.sParallax.fMidground1PosX += sIAPData.sCurrentStageData.vMidground1SpriteScale.x
ENDIF
//Midground 2 Position
sIAPData.sParallax.fMidground2PosX = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fMidground2PosX, CFIAP_BASE_MIDGROUND2_SPEED)
IF sIAPData.sParallax.fMidground2PosX < cfIAP_FACADE_WIDTH - (sIAPData.sCurrentStageData.vMidground2SpriteScale.x/2)
sIAPData.sParallax.fMidground2PosX += sIAPData.sCurrentStageData.vMidground2SpriteScale.x
ENDIF
//Midground 3 Position
sIAPData.sParallax.fMidground3PosX = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fMidground3PosX, CFIAP_BASE_MIDGROUND3_SPEED)
IF sIAPData.sParallax.fMidground3PosX < cfIAP_FACADE_WIDTH - (sIAPData.sCurrentStageData.vMidground3SpriteScale.x/2)
sIAPData.sParallax.fMidground3PosX += sIAPData.sCurrentStageData.vMidground3SpriteScale.x
ENDIF
//Foreground Position
sIAPData.sParallax.fForegroundPosX[0] = IAP_APPLY_SPEED_TO_VALUE(sIAPData.sParallax.fForegroundPosX[0], CFIAP_BASE_FOREGROUND_SPEED)
//If the 1st sprite is off screen shuffle the positions down
FLOAT fForeground0ScaleX = IAP_GET_FOREGROUND_X_SCALE(0)
IF sIAPData.sParallax.fForegroundPosX[0] < cfIAP_FACADE_WIDTH - (fForeground0ScaleX/2)
sIAPData.sParallax.fForegroundPosX[0] += (fForeground0ScaleX)
FOR i = 0 TO sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
IF i < sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
//If this foreground sprite is a pitfall and the next is not
//Subtract half the difference of the foreground scale and pitfall scale from this position
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] != ciIAP_PARALLAX_DEFAULT_SPRITE
AND sIAPData.sParallax.iActiveForegroundSpriteIndexes[i + 1] = ciIAP_PARALLAX_DEFAULT_SPRITE
sIAPData.sParallax.fForegroundPosX[i] -= ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2)
//If this foreground sprite is not a pitfall and the next is
//Add half the difference of the foreground scale and pitfall scale to this position
ELIF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_DEFAULT_SPRITE
AND sIAPData.sParallax.iActiveForegroundSpriteIndexes[i + 1] != ciIAP_PARALLAX_DEFAULT_SPRITE
sIAPData.sParallax.fForegroundPosX[i] += ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2)
ENDIF
sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = sIAPData.sParallax.iActiveForegroundSpriteIndexes[i + 1]
sIAPData.sParallax.iLinkedObjectIndexes[i] = sIAPData.sParallax.iLinkedObjectIndexes[i + 1]
ELSE
IF sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] != ciIAP_PARALLAX_DEFAULT_SPRITE
sIAPData.sParallax.fForegroundPosX[i] -= ((IAP_GET_CURRENT_PITFALL_SCALE() - sIAPData.sCurrentStageData.vForegroundSpriteScale.x) / 2)
ENDIF
sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_DEFAULT_SPRITE
sIAPData.sParallax.iLinkedObjectIndexes[i] = -1
ENDIF
ENDFOR
ENDIF
//Update foreground positions
FOR i = 1 TO sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
FLOAT fScaleX = IAP_GET_FOREGROUND_X_SCALE(i)
FLOAT fPrevScaleX = IAP_GET_FOREGROUND_X_SCALE(i - 1)
sIAPData.sParallax.fForegroundPosX[i] = sIAPData.sParallax.fForegroundPosX[i - 1] + (fPrevScaleX/2) + (fScaleX / 2)
ENDFOR
IF sIAPData.eCurrentState != IAP_CLIENT_STATE_RUNNING
EXIT
ENDIF
sIAPData.fDistanceTravelled = IAP_APPLY_SPEED_TO_VALUE(sIAPData.fDistanceTravelled, -CFIAP_BASE_FOREGROUND_SPEED)
IAP_UPDATE_MAX_MOON_DISTANCE()
ENDPROC
/// PURPOSE:
/// Updates the locations of weather effects
PROC IAP_PROCESS_WEATHER_EFFECTS()
IF NOT IAP_DOES_CURRENT_STAGE_HAVE_WEATHER_EFFECTS()
EXIT
ENDIF
sIAPData.vBaseWeatherPos.x = sIAPData.vBaseWeatherPos.x +@ (cfIAP_BLIZZARD_SPEED_X / 4)
sIAPData.vBaseWeatherPos.y = sIAPData.vBaseWeatherPos.y +@ (cfIAP_BLIZZARD_SPEED_Y / 4)
IF sIAPData.vBaseWeatherPos.x < cfIAP_FACADE_WIDTH - cfIAP_WEATHER_SPRITE_SCALE_X
OR sIAPData.vBaseWeatherPos.y > 1 + cfIAP_WEATHER_SPRITE_SCALE_Y
sIAPData.vBaseWeatherPos.x += (cfIAP_WEATHER_SPRITE_SCALE_X)
sIAPData.vBaseWeatherPos.y -= (cfIAP_WEATHER_SPRITE_SCALE_Y)
ENDIF
ENDPROC
// ------------------------------ INITIALISATION ------------------------------
/// PURPOSE:
/// Initialises all variables for the parallax background at the start of each stage
PROC IAP_INITIALISE_PARALLAX_DATA()
INT i
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_INITIALISE_PARALLAX_DATA - Initialising parallax data")
sIAPData.sParallax.fBackgroundPosX = cfIAP_FACADE_WIDTH + (sIAPData.sCurrentStageData.vBackgroundSpriteScale.x / 2)
sIAPData.sParallax.fMidground3PosX = cfIAP_FACADE_WIDTH + (sIAPData.sCurrentStageData.vMidground3SpriteScale.x / 2)
sIAPData.sParallax.fMidground2PosX = cfIAP_FACADE_WIDTH + (sIAPData.sCurrentStageData.vMidground2SpriteScale.x / 2)
sIAPData.sParallax.fMidground1PosX = cfIAP_FACADE_WIDTH + (sIAPData.sCurrentStageData.vMidground1SpriteScale.x / 2)
FLOAT fScaleX = sIAPData.sCurrentStageData.vForegroundSpriteScale.x
FOR i = 0 TO sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
sIAPData.sParallax.fForegroundPosX[i] = cfIAP_FACADE_WIDTH + (fScaleX * i) + (fScaleX / 2)
sIAPData.sParallax.iActiveForegroundSpriteIndexes[i] = ciIAP_PARALLAX_DEFAULT_SPRITE
ENDFOR
IF IAP_DOES_CURRENT_STAGE_HAVE_WEATHER_EFFECTS()
sIAPData.vBaseWeatherPos = INIT_VECTOR_2D(cfIAP_FACADE_WIDTH - (cfIAP_WEATHER_SPRITE_SCALE_X / 2), 1 + (cfIAP_WEATHER_SPRITE_SCALE_Y / 2))
ENDIF
ENDPROC
/// PURPOSE:
/// Resets all stage specific variables at the start of each stage
PROC IAP_RESET_STAGE_DATA()
INT i
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_RESET_STAGE_DATA - Resetting data for new stage: ", IAP_DEBUG_GET_IAP_STAGE_AS_STRING(sIAPData.eCurrentStage))
g_sCasinoArcadeInvadeAndPersuadeVars.iCurrentStage = ENUM_TO_INT(sIAPData.eCurrentStage)
//Populate Stage Data
IAP_INITIALISE_STAGE_DATA(sIAPData.eCurrentStage)
//Set old texture dictionary as no longer needed and prep the new one
IF NOT IS_STRING_NULL_OR_EMPTY(sIAPData.stLoadedStageTextureDictionary)
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED(sIAPData.stLoadedStageTextureDictionary)
ENDIF
sIAPData.stLoadedStageTextureDictionary = sIAPData.sCurrentStageData.stStageTextureDictionary
//Reset per stage score tracking variables
sIAPData.sScoreTracking.iPickupsCollected = 0
sIAPData.sScoreTracking.iOilCollected = 0
sIAPData.sScoreTracking.iEnemiesKilled = 0
//Reset procedural generation variables
sIAPData.sRandomGeneration.fNextSpawnDistance = -1
sIAPData.sRandomGeneration.eNextSpawnType = IAP_OBJECT_NONE
FOR i = 0 TO ciIAP_RANDOM_GENERATION_OBJECT_GROUP_MAX - 1
sIAPData.sRandomGeneration.fLastSpawnedFromGroup[i] = 0
#IF IS_DEBUG_BUILD
sIAPData.sRandomGeneration.iNumSpawnedFromGroup[i] = 0
#ENDIF
ENDFOR
//Reset object spawning variables
sIAPData.iNextObjectIndex = 0
sIAPData.iNextObjectToSpawn = 0
sIAPData.iNextOilIndex = 0
sIAPData.iNextOilToSpawn = 0
//Reset all object instances
FOR i = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
sIAPData.sObjectInstances[i].eObjectType = IAP_OBJECT_NONE
sIAPData.sObjectInstances[i].eState = IAP_OBJECT_STATE_DEFAULT
IF sIAPData.sObjectInstances[i].iOneShotSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[i].iOneShotSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[i].iOneShotSoundId)
sIAPData.sObjectInstances[i].iOneShotSoundId = -1
ENDIF
IF sIAPData.sObjectInstances[i].iLoopingSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[i].iLoopingSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[i].iLoopingSoundId)
sIAPData.sObjectInstances[i].iLoopingSoundId = -1
ENDIF
ENDFOR
IAP_STOP_LOOPING_FRONTEND_SOUND(sIAPData.iTallyLoopSoundId)
//Reset all explosions
FOR i = 0 TO ciIAP_MAX_EXPLOSIONS - 1
sIAPData.sExplosions[i].iAnimFrame = -1
ENDFOR
sIAPData.iNextExplosionIndex = 0
//Reset all projectiles
FOR i = 0 TO ciIAP_MAX_ENEMY_PROJECTILES - 1
sIAPData.sEnemyProjectileInstances[i].iShotTime = -HIGHEST_INT
ENDFOR
FOR i = 0 TO ciIAP_MAX_PLAYER_PROJECTILES - 1
sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime = -HIGHEST_INT
ENDFOR
//Reset stage variables
sIAPData.fDistanceTravelled = 0.0
sIAPData.fStageSpeedMod = sIAPData.sCurrentStageData.fBaseSpeed
IAP_INITIALISE_PARALLAX_DATA()
//Reset player tank variables
sIAPData.sPlayerTank.iTurretDirection = 0
sIAPData.sPlayerTank.iLastFrameTurretDirection = 0
sIAPData.sPlayerTank.vPosition.y = cfIAP_PLAYER_TANK_BASE_POS_Y + sIAPData.sCurrentStageData.fBaseY
sIAPData.sPlayerTank.vPosition.x = 0
#IF IS_DEBUG_BUILD
sIAPData.sDebugStruct.fLastObjectSpawned = 0.0
IF NOT sIAPData.sDebugStruct.bDontReplenishLivesEachStage
#ENDIF
IF sIAPData.bCheated
sIAPData.sPlayerTank.iLives = ciIAP_STARTING_LIVES_CHEATED
ELSE
sIAPData.sPlayerTank.iLives = ciIAP_STARTING_LIVES
ENDIF
#IF IS_DEBUG_BUILD
ENDIF
#ENDIF
sIAPData.sPlayerTank.iHealth = ciIAP_MAX_HEALTH
sIAPData.sPlayerTank.iDisplayHealth = 0
sIAPData.sPlayerTank.iLastDamagedTime = -HIGHEST_INT
sIAPData.sPlayerTank.iLastHealedTime = -HIGHEST_INT
sIAPData.sPlayerTank.iPlayerTankBitset = 0
sIAPData.sPlayerTank.stTankSprite = "tank_drive"
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
sIAPData.sPlayerTank.sAbovePlayerText.iStartTime = -HIGHEST_INT
sIAPData.sPlayerTank.iTankShootAnimFrame = 0
IAP_SET_PLAYER_TANK_STATE(IAP_PLAYER_TANK_STATE_DEFAULT)
IAP_SET_PLAYER_TURRET_STATE(IAP_PLAYER_TURRET_STATE_DEFAULT)
IAP_RESET_PLAYER_TANK_SOUNDS()
//HUD
sIAPData.iMiddleTextAnimFrame = 0
//Timers
IF HAS_NET_TIMER_STARTED(sIAPData.tdStageTimer)
RESET_NET_TIMER(sIAPData.tdStageTimer)
ENDIF
IF HAS_NET_TIMER_STARTED(sIAPData.tdStageOutroTimer)
RESET_NET_TIMER(sIAPData.tdStageOutroTimer)
ENDIF
IF HAS_NET_TIMER_STARTED(sIAPData.tdRetryTimer)
RESET_NET_TIMER(sIAPData.tdRetryTimer)
ENDIF
ENDPROC
PROC IAP_RESET_GAME_DATA_FOR_TITLE_SCREEN()
sIAPData.eCurrentStage = IAP_STAGE_IRAQ
IAP_WIPE_SCORE_TRACKING_STRUCT()
sIAPData.iCurrentInitial = 0
sIAPData.iInitials = 0
sIAPData.iLocalLbdPos = -1
IF IS_LONG_BIT_SET(sIAPData.iSpawnedObjectBitSet, ENUM_TO_INT(IAP_OBJECT_CRASHED_TANK))
CLEAR_LONG_BIT(sIAPData.iSpawnedObjectBitSet, ENUM_TO_INT(IAP_OBJECT_CRASHED_TANK))
ENDIF
ENDPROC
// ------------------------------ CLIENT STATE MACHINE ------------------------------
/// PURPOSE:
/// Updates the client state
PROC IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE eNewState)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_SET_CLIENT_STATE - State changed from ",
IAP_DEBUG_GET_IAP_CLIENT_STATE_AS_STRING(sIAPData.eCurrentState), " to ", IAP_DEBUG_GET_IAP_CLIENT_STATE_AS_STRING(eNewState))
sIAPData.eCurrentState = eNewState
ENDPROC
FUNC INT GET_TELEMETRY_LOCATION()
IF PLAYER_ID() != INVALID_PLAYER_INDEX()
SWITCH GET_SIMPLE_INTERIOR_TYPE_LOCAL_PLAYER_IS_IN()
CASE SIMPLE_INTERIOR_TYPE_ARCADE
RETURN HASH("SIMPLE_INTERIOR_TYPE_ARCADE")
BREAK
CASE SIMPLE_INTERIOR_TYPE_CASINO_APARTMENT
RETURN HASH("SIMPLE_INTERIOR_TYPE_CASINO_APARTMENT")
BREAK
DEFAULT
CDEBUG1LN(DEBUG_MINIGAME, "[[INVADE_PERSUADE_MAIN] [SET_TELEMETRY_LOCATION] not in valid arcade location, setting sArcadePlayStats.location = 0")
RETURN 0
BREAK
ENDSWITCH
ENDIF
CDEBUG2LN(DEBUG_MINIGAME, "[INVADE_PERSUADE_MAIN] [SET_TELEMETRY_LOCATION] Invalid Player ID, setting sArcadePlayStats.location = 0")
RETURN 0
ENDFUNC
PROC IAP_INITIALISE_LEADERBOARD_STAGE()
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_STATS_SENT)
sArcadePlayStats.numPlayers = 1
sArcadePlayStats.powerUps = sIAPData.sScoreTracking.iTotalPickupsCollected
sArcadePlayStats.kills = sIAPData.sScoreTracking.iTotalEnemiesKilled
sArcadePlayStats.score = IAP_GET_CURRENT_SCORE()
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_STATS_SENT)
sArcadePlayStats.location = GET_TELEMETRY_LOCATION()
ARCADE_SEND_PLAY_STATS()
ENDIF
STOP_AUDIO_SCENE("dlc_vw_am_ip_in_gameplay_scene")
START_AUDIO_SCENE("dlc_vw_am_ip_in_menus_scene")
IF IS_ACCOUNT_OVER_17_FOR_UGC()
IAP_START_LEADERBOARD_MOVIE_LOOP()
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEADERBOARD_START))
IAP_SORT_LEADERBOARD()
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_STAGE_LEADERBOARD)
ELSE
IAP_CLEAR_HELP_TEXT()
IAP_START_TITLE_INTRO_MOVIE_LOOP()
IAP_RESET_GAME_DATA_FOR_TITLE_SCREEN()
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Retry")
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_TITLE_SCREEN)
ENDIF
ENDPROC
/// PURPOSE:
/// Final cleanup procedure: removes all assets and resets player state.
PROC IAP_CLEANUP_AND_EXIT_CLIENT()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] - IAP_CLEANUP_AND_EXIT_CLIENT - Cleaning up and terminating the script")
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_STATS_SENT)
sArcadePlayStats.numPlayers = 1
sArcadePlayStats.powerUps = sIAPData.sScoreTracking.iTotalPickupsCollected
sArcadePlayStats.kills = sIAPData.sScoreTracking.iTotalEnemiesKilled
sArcadePlayStats.score = IAP_GET_CURRENT_SCORE()
sArcadePlayStats.location = GET_TELEMETRY_LOCATION()
ARCADE_SEND_PLAY_STATS()
ENDIF
ARCADE_CABINET_COMMON_CLEANUP()
//Set texture dictionaries as no longer needed
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED(IAP_GET_PLAYER_TEXTURE_DICT())
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("MPInvPersHud")
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("MPInvPersMessages")
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("MPInvPersMessages2")
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("MpInvPersCommon")
IF NOT IS_STRING_NULL_OR_EMPTY(sIAPData.stLoadedStageTextureDictionary)
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED(sIAPData.stLoadedStageTextureDictionary)
ENDIF
//Clear text
CLEAR_ADDITIONAL_TEXT(MINIGAME_TEXT_SLOT, FALSE)
//Clean up Audio
//TODO: May need handled in the penthouse instead?
IAP_RESET_PLAYER_TANK_SOUNDS()
INT i
FOR i = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF sIAPData.sObjectInstances[i].iOneShotSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[i].iOneShotSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[i].iOneShotSoundId)
sIAPData.sObjectInstances[i].iOneShotSoundId = -1
ENDIF
IF sIAPData.sObjectInstances[i].iLoopingSoundId > -1
STOP_SOUND(sIAPData.sObjectInstances[i].iLoopingSoundId)
RELEASE_SOUND_ID(sIAPData.sObjectInstances[i].iLoopingSoundId)
sIAPData.sObjectInstances[i].iLoopingSoundId = -1
ENDIF
ENDFOR
IAP_STOP_LOOPING_FRONTEND_SOUND(sIAPData.iTallyLoopSoundId)
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_STOP_MUSIC))
RELEASE_NAMED_SCRIPT_AUDIO_BANK("DLC_VINEWOOD/DLC_VW_AM_IP")
IF IS_AUDIO_SCENE_ACTIVE("dlc_vw_am_ip_in_gameplay_scene")
STOP_AUDIO_SCENE("dlc_vw_am_ip_in_gameplay_scene")
ENDIF
IF IS_AUDIO_SCENE_ACTIVE("dlc_vw_am_ip_in_menus_scene")
STOP_AUDIO_SCENE("dlc_vw_am_ip_in_menus_scene")
ENDIF
IAP_CLEAN_UP_BINKS()
IAP_CLEAR_HELP_TEXT()
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_FINISHED)
//Reset global player state for anims
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_NOT_PLAYING)
IAP_TRIGGER_AWARD_TICKERS()
TERMINATE_THIS_MULTIPLAYER_THREAD_NO_ARGS()
ENDPROC
//~~~~~ Client State Machine State Updates ~~~~~
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_INITIALISING
PROC IAP_PROCESS_CLIENT_STATE_INITIALISING()
ARCADE_CABINET_COMMON_INITIALIZATION()
ARCADE_GAMES_POSTFX_INIT(CASINO_ARCADE_GAME_INVADE_PERSUADE)
//Initialise static data
IAP_INITIALISE_OBJECT_DATA()
IAP_INITIALISE_PROJECTILE_TYPES()
IAP_INITIALISE_RANDOM_DISTANCE_BETWEEN_GROUPS()
IAP_INITIALISE_COLOURS()
IAP_INITIALISE_CHALLENGE_COMPLETION()
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_INTRO)
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_REQUESTING_ASSETS)
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_REQUESTING_ASSETS
PROC IAP_PROCESS_CLIENT_STATE_REQUESTING_ASSETS()
IF NOT IAP_HAVE_ALL_ASSETS_LOADED()
EXIT
ENDIF
//Start the intro movie
IAP_START_DEGENETRON_INTRO_MOVIE()
START_AUDIO_SCENE("dlc_vw_am_ip_in_menus_scene")
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_DEGENETRON)
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_DEGENETRON
PROC IAP_PROCESS_CLIENT_STATE_DEGENETRON()
//Wait for the intro movie to finish
IF NOT IAP_DRAW_DEGENETRON_INTRO_MOVIE()
EXIT
ENDIF
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_RON_OIL)
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_RON_OIL
PROC IAP_PROCESS_CLIENT_STATE_RON_OIL()
IF NOT HAS_NET_TIMER_STARTED(sIAPData.tdRonOilTimer)
REINIT_NET_TIMER(sIAPData.tdRonOilTimer)
ENDIF
IF NOT HAS_NET_TIMER_EXPIRED(sIAPData.tdRonOilTimer, ciIAP_RON_OIL_SPLASH_FADE_TIME)
FLOAT fAlpha = TO_FLOAT(GET_NET_TIMER_DIFFERENCE_WITH_CURRENT_TIME(sIAPData.tdRonOilTimer)) / ciIAP_RON_OIL_SPLASH_FADE_TIME
INT iAlpha = ROUND(INTERP_FLOAT(0, 255, fAlpha, INTERPTYPE_SMOOTHSTEP))
IAP_DRAW_RON_OIL_INTRO(iAlpha)
ELSE
IAP_DRAW_RON_OIL_INTRO()
ENDIF
IF NOT HAS_NET_TIMER_EXPIRED(sIAPData.tdRonOilTimer, ciIAP_RON_OIL_SPLASH_FADE_TIME + ciIAP_RON_OIL_SPLASH_HOLD_TIME)
EXIT
ENDIF
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_TITLE_SCREEN))
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STARTED)
IAP_START_TITLE_INTRO_MOVIE_LOOP()
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_TITLE_SCREEN)
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_TITLE_SCREEN
PROC IAP_PROCESS_CLIENT_STATE_TITLE_SCREEN()
IAP_DRAW_TITLE_SCREEN()
IAP_PROCESS_TITLE_SCREEN_HELP_TEXT()
IAP_PROCESS_TITLE_INTRO_AUDIO()
IAP_PROCESS_CHEATING()
IF NOT IAP_HAS_PLAYER_PRESSED_START()
EXIT
ENDIF
CLEAR_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STARTED)
CLEAR_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_INTRO_MUSIC_STOPPED)
IAP_RESET_STAGE_DATA()
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_STOP_MUSIC))
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Start")
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_STAGE_LOADING)
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEVEL_BRIEF))
IAP_STOP_TITLE_INTRO_MOVIE_LOOP()
ARCADE_INITIALISE_PLAY_STATS(FALSE)
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_STAGE_LOADING)
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_STAGE_LOADING
PROC IAP_PROCESS_CLIENT_STATE_STAGE_LOADING()
IF NOT HAS_NET_TIMER_STARTED(sIAPData.tdStageLoadingTimer)
REINIT_NET_TIMER(sIAPData.tdStageLoadingTimer)
ENDIF
IAP_PROCESS_OBJECT_HELP_TEXT()
IAP_DRAW_STAGE_LOADING_SCREEN()
IF NOT IAP_HAVE_CURRENT_STAGE_ASSETS_LOADED()
EXIT
ENDIF
IF NOT HAS_NET_TIMER_EXPIRED(sIAPData.tdStageLoadingTimer, ciIAP_STAGE_LOADING_TIME)
#IF IS_DEBUG_BUILD
AND NOT IS_DEBUG_KEY_JUST_PRESSED(KEY_J, KEYBOARD_MODIFIER_NONE, "Skip Loading Screen")
#ENDIF
EXIT
ENDIF
RESET_NET_TIMER(sIAPData.tdStageLoadingTimer)
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEVEL_PLAY))
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_STAGE_INTRO)
STOP_AUDIO_SCENE("dlc_vw_am_ip_in_menus_scene")
START_AUDIO_SCENE("dlc_vw_am_ip_in_gameplay_scene")
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Get_Ready")
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_STAGE_INTRO
PROC IAP_PROCESS_CLIENT_STATE_STAGE_INTRO()
IAP_PROCESS_PLAYER_TANK_STATE()
IAP_PROCESS_WEATHER_EFFECTS()
IAP_PROCESS_OBJECT_HELP_TEXT()
IAP_DRAW_STAGE_INTRO()
IF NOT IAP_IS_PLAYER_TANK_IN_START_POSITION()
EXIT
ENDIF
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_PLAYING)
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_RUNNING)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Go")
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_RUNNING
PROC IAP_PROCESS_CLIENT_STATE_RUNNING()
IF NOT HAS_NET_TIMER_STARTED(sIAPData.tdStageTimer)
REINIT_NET_TIMER(sIAPData.tdStageTimer)
sIAPData.iMiddleTextAnimFrame = 0
ENDIF
IAP_PROCESS_SCROLLING_STAGE()
IAP_PROCESS_INPUT_PRE_MOVEMENT()
IAP_PROCESS_STAGE_OBJECTS()
IAP_PROCESS_PLAYER_TANK_STATE()
IAP_PROCESS_PLAYER_TURRET_STATE()
IAP_PROCESS_INPUT_POST_MOVEMENT()
IAP_PROCESS_PLAYER_PROJECTILES()
IAP_PROCESS_ENEMY_PROJECTILES()
IAP_PROCESS_EXPLOSIONS()
IAP_PROCESS_SCORE_TEXT()
IAP_PROCESS_WEATHER_EFFECTS()
IAP_PROCESS_COLLISIONS()
IAP_PROCESS_PLAYER_SCORE()
IAP_PROCESS_OBJECT_HELP_TEXT()
IAP_DRAW_STAGE_RUNNING()
IF sIAPData.sPlayerTank.iHealth = 0
AND sIAPData.sPlayerTank.iLives < 0
#IF IS_DEBUG_BUILD
AND sIAPData.sDebugStruct.bDontFailWhenOutOfLives = FALSE
#ENDIF
IAP_STOP_TANK_WEAPON_LOOP()
sIAPData.iMiddleTextAnimFrame = 0
SET_MP_INT_CHARACTER_STAT(MP_STAT_IAP_MAX_MOON_DIST, sIAPData.iCachedMaxMoonDistance)
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_GAMEOVER_STAGE)
sIAPData.sPlayerTank.iTankBaseAnimFrame = 0
RESET_NET_TIMER(sIAPData.tdStageTimer)
sIAPData.iEndLivesToShow = 0
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_LIVES_SCORE_ADDED)
sIAPData.iEndArmourToShow = 0
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_ARMOUR_SCORE_ADDED)
sIAPData.iEndDistanceToShow = FLOOR(sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION)
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_DEAD)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Game_Over")
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_STAGE_CLEAR))
EXIT
ENDIF
IF (sIAPData.sCurrentStageData.fStageDistance != ciIAP_STAGE_INFINITE_LENGTH
AND (sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION) >= sIAPData.sCurrentStageData.fStageDistance)
#IF IS_DEBUG_BUILD
OR IS_KEYBOARD_KEY_PRESSED(KEY_J)
#ENDIF
IAP_STOP_TANK_WEAPON_LOOP()
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_LEVEL_COMPLETE)
sIAPData.iMiddleTextAnimFrame = 0
IAP_SET_PLAYER_TURRET_STATE(IAP_PLAYER_TURRET_STATE_DEFAULT)
SET_MP_INT_CHARACTER_STAT(MP_STAT_IAP_MAX_MOON_DIST, sIAPData.iCachedMaxMoonDistance)
IAP_UPDATE_LIVES_CHALLENGE()
sIAPData.iEndLivesToShow = sIAPData.sPlayerTank.iLives
sIAPData.iEndArmourToShow = sIAPData.sPlayerTank.iHealth
sIAPData.iEndDistanceToShow = FLOOR(sIAPData.fDistanceTravelled / cfIAP_DISTANCE_CONVERSION)
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_STAGE_OUTRO)
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Stage_Clear")
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_STAGE_CLEAR))
RESET_NET_TIMER(sIAPData.tdStageTimer)
ENDIF
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_GAMEOVER_STAGE
PROC IAP_PROCESS_CLIENT_STATE_GAMEOVER_STAGE()
IF NOT HAS_NET_TIMER_STARTED(sIAPData.tdRetryTimer)
REINIT_NET_TIMER(sIAPData.tdRetryTimer)
ENDIF
IAP_PROCESS_STAGE_OBJECTS()
IAP_PROCESS_PLAYER_TURRET_STATE()
IAP_PROCESS_PLAYER_TANK_STATE()
IAP_PROCESS_WEATHER_EFFECTS()
IAP_PROCESS_EXPLOSIONS()
IAP_PROCESS_SCORE_TEXT()
IAP_PROCESS_PLAYER_SCORE()
IAP_PROCESS_OBJECT_HELP_TEXT()
IAP_DRAW_STAGE_GAMEOVER()
IF NOT IAP_PROCESSED_FINAL_STAGE_SCORE()
EXIT
ENDIF
IF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_END_MUSIC_TRIGGERED)
AND HAS_NET_TIMER_EXPIRED(sIAPData.tdRetryTimer, ciIAP_DEATH_TIME - 2000)
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEVEL_END))
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_END_MUSIC_TRIGGERED)
ENDIF
IF NOT HAS_NET_TIMER_EXPIRED(sIAPData.tdRetryTimer, ciIAP_DEATH_TIME)
EXIT
ENDIF
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_GAMEOVER_SCREEN)
IAP_INITIALISE_LEADERBOARD_STAGE()
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_STAGE_OUTRO
PROC IAP_PROCESS_CLIENT_STATE_STAGE_OUTRO()
IAP_PROCESS_STAGE_OBJECTS()
IAP_PROCESS_PLAYER_TURRET_STATE()
IAP_PROCESS_PLAYER_TANK_STATE()
IAP_PROCESS_PLAYER_PROJECTILES()
IAP_PROCESS_EXPLOSIONS()
IAP_PROCESS_SCORE_TEXT()
IAP_PROCESS_WEATHER_EFFECTS()
IAP_PROCESS_PLAYER_SCORE()
IAP_PROCESS_OBJECT_HELP_TEXT()
IAP_DRAW_STAGE_OUTRO()
IF IAP_IS_PLAYER_TANK_IN_END_POSITION()
IF NOT IAP_PROCESSED_FINAL_STAGE_SCORE()
EXIT
ENDIF
IF NOT HAS_NET_TIMER_STARTED(sIAPData.tdStageOutroTimer)
REINIT_NET_TIMER(sIAPData.tdStageOutroTimer)
ELIF HAS_NET_TIMER_EXPIRED(sIAPData.tdStageOutroTimer, ciIAP_OUTRO_TEXT_TIME)
sIAPData.eCurrentStage = INT_TO_ENUM(IAP_STAGE, ENUM_TO_INT(sIAPData.eCurrentStage) + 1)
IF sIAPData.eCurrentStage = IAP_STAGE_MAX
IAP_INITIALISE_LEADERBOARD_STAGE()
ELSE
IAP_RESET_STAGE_DATA()
IAP_SET_GLOBAL_PLAYER_STATE(CASINO_ARCADE_INVADE_PERSUADE_PLAYER_STATE_STAGE_LOADING)
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEVEL_BRIEF))
IF IS_AUDIO_SCENE_ACTIVE("dlc_vw_am_ip_in_gameplay_scene")
STOP_AUDIO_SCENE("dlc_vw_am_ip_in_gameplay_scene")
ENDIF
START_AUDIO_SCENE("dlc_vw_am_ip_in_menus_scene")
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_STAGE_LOADING)
ENDIF
RESET_NET_TIMER(sIAPData.tdStageOutroTimer)
ELIF NOT IS_BIT_SET(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_END_MUSIC_TRIGGERED)
AND HAS_NET_TIMER_EXPIRED(sIAPData.tdStageOutroTimer, ciIAP_OUTRO_TEXT_TIME - 2000)
SET_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_END_MUSIC_TRIGGERED)
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEVEL_END))
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Processing for the client state: IAP_CLIENT_STATE_STAGE_LEADERBOARD
PROC IAP_PROCESS_CLIENT_STATE_STAGE_LEADERBOARD()
IAP_DRAW_LEADERBOARD()
IAP_PROCESS_LEADERBOARD_ENTRY()
IAP_PROCESS_LEADERBOARD_HELP_TEXT()
IF NOT IAP_HAS_PLAYER_PRESSED_START()
EXIT
ENDIF
IF IAP_GET_PLAYER_LEADERBOARD_POSITION() < ciCASINO_ARCADE_LEADERBOARD_POSITIONS
sIAPData.sLeaderboard[IAP_GET_PLAYER_LEADERBOARD_POSITION()].bPlayer = FALSE
sIAPData.sLeaderboard[IAP_GET_PLAYER_LEADERBOARD_POSITION()].iInitials = sIAPData.iInitials
ENDIF
IAP_CLEAR_HELP_TEXT()
IAP_STOP_LEADERBOARD_MOVIE_LOOP()
IAP_START_TITLE_INTRO_MOVIE_LOOP()
IAP_RESET_GAME_DATA_FOR_TITLE_SCREEN()
IAP_PLAY_FIRE_AND_FORGET_FRONTEND_SOUND("Frontend_Retry")
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_TITLE_SCREEN)
ENDPROC
//~~~~~ Client State Machine Main Update ~~~~~
/// PURPOSE:
/// Processes the client state machine
PROC IAP_PROCESS_CLIENT_STATE_MACHINE()
SWITCH sIAPData.eCurrentState
CASE IAP_CLIENT_STATE_INITIALISING
IAP_PROCESS_CLIENT_STATE_INITIALISING()
BREAK
CASE IAP_CLIENT_STATE_REQUESTING_ASSETS
IAP_PROCESS_CLIENT_STATE_REQUESTING_ASSETS()
BREAK
CASE IAP_CLIENT_STATE_DEGENETRON
IAP_PROCESS_CLIENT_STATE_DEGENETRON()
BREAK
CASE IAP_CLIENT_STATE_RON_OIL
IAP_PROCESS_CLIENT_STATE_RON_OIL()
BREAK
CASE IAP_CLIENT_STATE_TITLE_SCREEN
IAP_PROCESS_CLIENT_STATE_TITLE_SCREEN()
BREAK
CASE IAP_CLIENT_STATE_STAGE_LOADING
IAP_PROCESS_CLIENT_STATE_STAGE_LOADING()
BREAK
CASE IAP_CLIENT_STATE_STAGE_INTRO
IAP_PROCESS_CLIENT_STATE_STAGE_INTRO()
BREAK
CASE IAP_CLIENT_STATE_RUNNING
IAP_PROCESS_CLIENT_STATE_RUNNING()
BREAK
CASE IAP_CLIENT_STATE_GAMEOVER_STAGE
IAP_PROCESS_CLIENT_STATE_GAMEOVER_STAGE()
BREAK
CASE IAP_CLIENT_STATE_STAGE_OUTRO
IAP_PROCESS_CLIENT_STATE_STAGE_OUTRO()
BREAK
CASE IAP_CLIENT_STATE_STAGE_LEADERBOARD
IAP_PROCESS_CLIENT_STATE_STAGE_LEADERBOARD()
BREAK
CASE IAP_CLIENT_STATE_CLEANUP
IAP_CLEANUP_AND_EXIT_CLIENT()
BREAK
CASE IAP_CLIENT_STATE_FINISHED
//Do nothing
BREAK
ENDSWITCH
ENDPROC
#IF IS_DEBUG_BUILD
// ------------------------------ DEBUG ------------------------------
/// PURPOSE:
/// Skips to another stage of the game
PROC IAP_DEBUG_SKIP_TO_STAGE(IAP_STAGE eStage)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_SKIP_TO_STAGE - SKIPPING TO STAGE: ", IAP_DEBUG_GET_IAP_STAGE_AS_STRING(eStage))
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_STOP_MUSIC))
sIAPData.eCurrentStage = eStage
IAP_CLEAN_UP_BINKS()
IAP_WIPE_SCORE_TRACKING_STRUCT()
IAP_RESET_STAGE_DATA()
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_STAGE_LOADING)
IF IS_AUDIO_SCENE_ACTIVE("dlc_vw_am_ip_in_gameplay_scene")
STOP_AUDIO_SCENE("dlc_vw_am_ip_in_gameplay_scene")
ENDIF
IF NOT IS_AUDIO_SCENE_ACTIVE("dlc_vw_am_ip_in_menus_scene")
START_AUDIO_SCENE("dlc_vw_am_ip_in_menus_scene")
ENDIF
IAP_TRIGGER_MUSIC_EVENT(IAP_GET_MUSIC_EVENT_STRING(IAP_MUSIC_EVENT_LEVEL_BRIEF))
ENDPROC
/// PURPOSE:
/// Sets the given widget group to be the parent for any widgets created by the minigame.
PROC IAP_DEBUG_SET_PARENT_WIDGET_GROUP(WIDGET_GROUP_ID parentWidgetGroup)
sIAPData.sDebugStruct.widgetScrollingMinigame = parentWidgetGroup
ENDPROC
/// PURPOSE:
/// Creates all of the debug widgets.
PROC IAP_DEBUG_CREATE_WIDGETS()
IF NOT sIAPData.sDebugStruct.bDebugCreatedWidgets
AND sIAPData.sDebugStruct.widgetScrollingMinigame != NULL
SET_CURRENT_WIDGET_GROUP(sIAPData.sDebugStruct.widgetScrollingMinigame)
START_WIDGET_GROUP("Scrolling Arcade Cabinet Minigame")
ADD_WIDGET_BOOL("bDrawCollisionDebug", sIAPData.sDebugStruct.bDrawCollisionDebug)
ADD_WIDGET_BOOL("bBlockDrawing", g_bBlockArcadeCabinetDrawing)
ADD_WIDGET_BOOL("g_bMinimizeArcadeCabinetDrawing", g_bMinimizeArcadeCabinetDrawing)
ADD_WIDGET_BOOL("bDisableSFX", sIAPData.sDebugStruct.bDisableSFX)
ADD_WIDGET_BOOL("bDisableMusic", sIAPData.sDebugStruct.bDisableMusic)
ADD_WIDGET_BOOL("bEnableAllChallenges", sIAPData.sDebugStruct.bEnableAllChallenges)
ADD_WIDGET_BOOL("bDisableAllChallenges", sIAPData.sDebugStruct.bDisableAllChallenges)
ADD_WIDGET_BOOL("bTriggerChallenge0", sIAPData.sDebugStruct.bTriggerChallenge0)
ADD_WIDGET_BOOL("bTriggerChallenge1", sIAPData.sDebugStruct.bTriggerChallenge1)
ADD_WIDGET_BOOL("bTriggerChallenge2", sIAPData.sDebugStruct.bTriggerChallenge2)
ADD_WIDGET_BOOL("bTriggerChallenge3", sIAPData.sDebugStruct.bTriggerChallenge3)
ADD_WIDGET_BOOL("bTriggerChallenge4", sIAPData.sDebugStruct.bTriggerChallenge4)
ADD_WIDGET_FLOAT_SLIDER("Midground1PosOffset", cfIAP_MIDGROUND1_Y_OFFSET, -1, 1, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Midground2PosOffset", cfIAP_MIDGROUND2_Y_OFFSET, -1, 1, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Midground3PosOffset", cfIAP_MIDGROUND3_Y_OFFSET, -1, 1, 0.001)
ADD_WIDGET_FLOAT_SLIDER("BackgroundPosOffset", cfIAP_BACKGROUND_Y_OFFSET, -1, 1, 0.001)
ADD_WIDGET_INT_READ_ONLY("iRectsDrawnThisFrame", iRectsDrawnThisFrame)
ADD_WIDGET_INT_READ_ONLY("iSpritesDrawnThisFrame", iSpritesDrawnThisFrame)
ADD_WIDGET_INT_READ_ONLY("iDebugLinesDrawnThisFrame", iDebugLinesDrawnThisFrame)
START_WIDGET_GROUP("Player Tank")
ADD_WIDGET_FLOAT_SLIDER("Max Speed", cfIAP_PLAYER_TANK_MAX_SPEED_MOD, 0, 1, 0.001)
ADD_WIDGET_INT_SLIDER("Accel Time", ciIAP_PLAYER_TANK_SPEED_MOD_TIME, 0, 10000, 250)
ADD_WIDGET_INT_SLIDER("Jump Up Duration", ciIAP_PLAYER_TANK_JUMP_TIME_UP, 0, 2000, 50)
ADD_WIDGET_INT_SLIDER("Jump Interval", ciIAP_PLAYER_TANK_JUMP_INTERVAL, 0, 5000, 50)
ADD_WIDGET_FLOAT_SLIDER("Jump Height", cfIAP_PLAYER_TANK_JUMP_HEIGHT, -1, 0, 0.001)
ADD_WIDGET_BOOL("bNoDamage", sIAPData.sDebugStruct.bNoDamage)
ADD_WIDGET_BOOL("bDontFailWhenOutOfLives", sIAPData.sDebugStruct.bDontFailWhenOutOfLives)
ADD_WIDGET_BOOL("bDontReplenishLivesEachStage", sIAPData.sDebugStruct.bDontReplenishLivesEachStage)
ADD_WIDGET_BOOL("bLoseWeaponOnHit", sIAPData.sDebugStruct.bLoseWeaponOnHit)
ADD_WIDGET_BOOL("bNoAccel", sIAPData.sDebugStruct.bNoAccel)
ADD_WIDGET_BOOL("bAccelInAir", sIAPData.sDebugStruct.bAccelInAir)
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Score Tally")
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_POS_Y", cfIAP_STAGE_CLEAR_TALLY_TEXT_POS_Y, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_TITLE_COLUMN_WRAP_MIN", cfIAP_STAGE_CLEAR_TALLY_TEXT_TITLE_COLUMN_WRAP_MIN, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_TITLE_COLUMN_WRAP_MAX", cfIAP_STAGE_CLEAR_TALLY_TEXT_TITLE_COLUMN_WRAP_MAX, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_VALUE_COLUMN_WRAP_MIN", cfIAP_STAGE_CLEAR_TALLY_TEXT_VALUE_COLUMN_WRAP_MIN, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_VALUE_COLUMN_WRAP_MAX", cfIAP_STAGE_CLEAR_TALLY_TEXT_VALUE_COLUMN_WRAP_MAX, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_SPACING_Y", cfIAP_STAGE_CLEAR_TALLY_TEXT_SPACING_Y, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_RECT_OFFSET_X", cfIAP_STAGE_CLEAR_TALLY_RECT_OFFSET_X, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_RECT_OFFSET_Y", cfIAP_STAGE_CLEAR_TALLY_RECT_OFFSET_Y, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_RECT_WIDTH", cfIAP_STAGE_CLEAR_TALLY_RECT_WIDTH, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_RECT_HEIGHT", cfIAP_STAGE_CLEAR_TALLY_RECT_HEIGHT, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_STAGE_CLEAR_TALLY_TEXT_SCALE", cfIAP_STAGE_CLEAR_TALLY_TEXT_SCALE, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_LIVES_TEXT_OFFSET_X", cfIAP_LIVES_TEXT_OFFSET_X, -1.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_LIVES_TEXT_OFFSET_Y", cfIAP_LIVES_TEXT_OFFSET_Y, -1.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_LIVES_TEXT_WRAP_MAX", cfIAP_LIVES_TEXT_WRAP_MAX, -1.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_SCORE_TEXT_OFFSET_Y", cfIAP_SCORE_TEXT_OFFSET_Y, -1.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_DISTANCE_TEXT_BEST_OFFSET_X", cfIAP_DISTANCE_TEXT_BEST_OFFSET_X, -1.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_DISTANCE_TEXT_OFFSET_X", cfIAP_DISTANCE_TEXT_OFFSET_X, -1.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("cfIAP_DISTANCE_TEXT_OFFSET_Y", cfIAP_DISTANCE_TEXT_OFFSET_Y, -1.0, 1.0, 0.001)
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Stage Speed")
ADD_WIDGET_FLOAT_SLIDER("Max Stage Speed", cfIAP_MAX_STAGE_SPEED_MOD, 1.0, 3.0, 0.05)
ADD_WIDGET_FLOAT_SLIDER("Current Stage Speed", sIAPData.fStageSpeedMod, 1.0, 3.0, 0.05)
ADD_WIDGET_FLOAT_SLIDER("Large Oil Speed Boost", cfIAP_LARGE_OIL_SPEED_BOOST, 0, 1.0, 0.005)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil Speed Boost", cfIAP_MEDIUM_OIL_SPEED_BOOST, 0, 1.0, 0.005)
ADD_WIDGET_FLOAT_SLIDER("Small Oil Speed Boost", cfIAP_SMALL_OIL_SPEED_BOOST, 0, 1.0, 0.005)
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Procedural Level")
ADD_WIDGET_FLOAT_SLIDER("Min Distance Between Spawns Start", cfIAP_RANDOM_MIN_DIST_BETWEEN_SPAWNS_START, 0, 20, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Max Distance Between Spawns Start", cfIAP_RANDOM_MAX_DIST_BETWEEN_SPAWNS_START, 0, 20, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Min Distance Between Spawns End", cfIAP_RANDOM_MIN_DIST_BETWEEN_SPAWNS_END, 0, 20, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Max Distance Between Spawns End", cfIAP_RANDOM_MAX_DIST_BETWEEN_SPAWNS_END, 0, 20, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Distance To End Spawn Distance", cfIAP_RANDOM_DISTANCE_TO_END_SPAWN_DIST, 0, 10000, 100)
ADD_WIDGET_FLOAT_READ_ONLY("Current Min Dist Between Spawns", sIAPData.sRandomGeneration.fMinDistBetweenSpawns)
ADD_WIDGET_FLOAT_READ_ONLY("Current Max Dist Between Spawns", sIAPData.sRandomGeneration.fMaxDistBetweenSpawns)
ADD_WIDGET_BOOL("bRandomPickupsOnly", sIAPData.sDebugStruct.bRandomPickupsOnly)
START_WIDGET_GROUP("Spawn Groups")
START_WIDGET_GROUP("Group - Pitfalls")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Pitfall to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Ground Enemy")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ground Enemy to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Jet")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Jet to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Drone")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Drone to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Rare Pickup")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Rare Pickup to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Common Pickup")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Common Pickup to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Small Oil")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Small Oil to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Medium Oil")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Medium Oil to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Large Oil")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Large Oil to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Group - Ledges")
ADD_WIDGET_FLOAT_READ_ONLY("Last Spawned", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES])
ADD_WIDGET_INT_READ_ONLY("Total Spawned", sIAPData.sRandomGeneration.iNumSpawnedFromGroup[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES])
START_WIDGET_GROUP("Group Min Spawn Distances")
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Pitfall", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PITFALLS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Ground Enemy", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_GROUND_ENEMIES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Jet", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_JETS], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Drone", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_DRONES], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Rare Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_RARE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Common Pickup", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_PICKUPS_COMMON], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Small Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_SMALL], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Medium Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_MEDIUM], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Large Oil", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_OIL_LARGE], 0, 100, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Ledge to Next Ledge", sIAPData.sRandomGeneration.fMinDistancesBetweenGroups[ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES][ciIAP_RANDOM_GENERATION_OBJECT_GROUP_LEDGES], 0, 100, 0.25)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
ARCADE_GAMES_POSTFX_WIDGET_CREATE()
STOP_WIDGET_GROUP()
CLEAR_CURRENT_WIDGET_GROUP(sIAPData.sDebugStruct.widgetScrollingMinigame)
sIAPData.sDebugStruct.bDebugCreatedWidgets = TRUE
ENDIF
ENDPROC
/// PURPOSE:
/// Turns all challenge stats on or off
PROC IAP_ENABLE_ALL_CHALLENGES(BOOL bEnable)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_ENABLE_ALL_CHALLENGES - bEnable ", bEnable)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_GOLD_TANK, bEnable)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_0, bEnable)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_1, bEnable)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_2, bEnable)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_3, bEnable)
SET_MP_BOOL_CHARACTER_STAT(MP_STAT_IAP_CHALLENGE_4, bEnable)
ENDPROC
/// PURPOSE:
/// Dumps the current state of the game to the logs
/// Automatically called when a bug is entered
PROC IAP_DEBUG_DUMP_DATA_TO_LOGS()
INT i
ARCADE_CABINET_DUMP_DATA_TO_CONSOLE()
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_DUMP_DATA_TO_LOGS - Dumping data...")
//General
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- GENERAL -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eCurrentState = ", IAP_DEBUG_GET_IAP_CLIENT_STATE_AS_STRING(sIAPData.eCurrentState))
//Objects
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- OBJECTS -----")
FOR i = 0 TO ciIAP_MAX_ACTIVE_OBJECTS - 1
IF sIAPData.sObjectInstances[i].eObjectType = IAP_OBJECT_NONE
RELOOP
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eObjectType[",i,"] = ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(sIAPData.sObjectInstances[i].eObjectType))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eState[",i,"] = ", IAP_DEBUG_GET_IAP_OBJECT_STATE_AS_STRING(sIAPData.sObjectInstances[i].eState))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] vPosition[",i,"] = (", sIAPData.sObjectInstances[i].vPosition.x, ", ", sIAPData.sObjectInstances[i].vPosition.y, ")")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iSpawnTime[",i,"] = ", sIAPData.sObjectInstances[i].iSpawnTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iHealth[",i,"] = ", sIAPData.sObjectInstances[i].iHealth)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLastDamagedTime[",i,"] = ", sIAPData.sObjectInstances[i].iLastDamagedTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLastShotTime[",i,"] = ", sIAPData.sObjectInstances[i].iLastShotTime)
ENDFOR
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- ENEMY PROJECTILES -----")
FOR i = 0 TO ciIAP_MAX_ENEMY_PROJECTILES - 1
IF sIAPData.sEnemyProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_NONE
OR sIAPData.sEnemyProjectileInstances[i].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eProjectileType[",i,"] = ", IAP_DEBUG_GET_IAP_PROJECTILE_TYPE_AS_STRING(sIAPData.sEnemyProjectileInstances[i].eProjectileType))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iShotTime[",i,"] = ", sIAPData.sEnemyProjectileInstances[i].iShotTime)
ENDFOR
//Spawning
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- SPAWNING -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iNextObjectToSpawn = ", sIAPData.iNextObjectToSpawn)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iNextObjectIndex = ", sIAPData.iNextObjectIndex)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iNextOilToSpawn = ", sIAPData.iNextOilToSpawn)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iNextOilIndex = ", sIAPData.iNextOilIndex)
//Procedural Generation
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- PROCEDURAL GENERATION -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] fNextSpawnDistance = ", sIAPData.sRandomGeneration.fNextSpawnDistance)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eNextSpawnType = ", IAP_DEBUG_GET_IAP_OBJECT_AS_STRING(sIAPData.sRandomGeneration.eNextSpawnType))
FOR i = 0 TO ciIAP_RANDOM_GENERATION_OBJECT_GROUP_MAX - 1
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] fLastSpawnedFromGroup[",i,"] = ", sIAPData.sRandomGeneration.fLastSpawnedFromGroup[i])
ENDFOR
//Stage
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- STAGE -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eCurrentStage = ", IAP_DEBUG_GET_IAP_STAGE_AS_STRING(sIAPData.eCurrentStage))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] fDistanceTravelled = ", sIAPData.fDistanceTravelled)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] fStageSpeedMod = ", sIAPData.fStageSpeedMod)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] stLoadedStageTextureDictionary = ", sIAPData.stLoadedStageTextureDictionary)
FOR i = 0 TO sIAPData.sCurrentStageData.iMaxActiveForegroundSprites - 1
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iActiveForegroundSpriteIndexes[",i,"] = ", sIAPData.sParallax.iActiveForegroundSpriteIndexes[i])
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] fForegroundPosX[",i,"] = ", sIAPData.sParallax.fForegroundPosX[i])
ENDFOR
//Player Tank
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- PLAYER TANK -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eTankState = ", IAP_DEBUG_GET_IAP_PLAYER_TANK_STATE_AS_STRING(sIAPData.sPlayerTank.eTankState))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eTurretState = ", IAP_DEBUG_GET_IAP_PLAYER_TURRET_STATE_AS_STRING(sIAPData.sPlayerTank.eTurretState))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eWeaponType = ", IAP_DEBUG_GET_IAP_PLAYER_WEAPON_AS_STRING(sIAPData.sPlayerTank.eWeaponType))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] vPosition = (", sIAPData.sPlayerTank.vPosition.x, ", ", sIAPData.sPlayerTank.vPosition.y, ")")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iTurretDirection = ", sIAPData.sPlayerTank.iTurretDirection)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iTurretLastShootTime = ", sIAPData.sPlayerTank.iTurretLastShootTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLastJumpTime = ", sIAPData.sPlayerTank.iLastJumpTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLastDamagedTime = ", sIAPData.sPlayerTank.iLastDamagedTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLastHealedTime = ", sIAPData.sPlayerTank.iLastHealedTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLastSmokeTime = ", sIAPData.sPlayerTank.iLastSmokeTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iRespawnTime = ", sIAPData.sPlayerTank.iRespawnTime)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iLives = ", sIAPData.sPlayerTank.iLives)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iHealth = ", sIAPData.sPlayerTank.iHealth)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iPlayerTankBitset = ", sIAPData.sPlayerTank.iPlayerTankBitset)
FOR i = 0 TO ciIAP_MAX_PLAYER_PROJECTILES - 1
IF sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType = IAP_PROJECTILE_TYPE_NONE
OR sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime = -HIGHEST_INT
RELOOP
ENDIF
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] eProjectileType[",i,"] = ", IAP_DEBUG_GET_IAP_PROJECTILE_TYPE_AS_STRING(sIAPData.sPlayerTank.sProjectileInstances[i].eProjectileType))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iShotTime[",i,"] = ", sIAPData.sPlayerTank.sProjectileInstances[i].iShotTime)
ENDFOR
//Scoring
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- SCORE TRACKING -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iScoreFromPickups = ", sIAPData.sScoreTracking.iScoreFromPickups)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iPickupsCollected = ", sIAPData.sScoreTracking.iPickupsCollected)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iTotalPickupsCollected = ", sIAPData.sScoreTracking.iTotalPickupsCollected)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iScoreFromEnemies = ", sIAPData.sScoreTracking.iScoreFromEnemies)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iEnemiesKilled = ", sIAPData.sScoreTracking.iEnemiesKilled)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iTotalEnemiesKilled = ", sIAPData.sScoreTracking.iTotalEnemiesKilled)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iScoreFromOil = ", sIAPData.sScoreTracking.iScoreFromOil)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iOilCollected = ", sIAPData.sScoreTracking.iOilCollected)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iTotalOilCollected = ", sIAPData.sScoreTracking.iTotalOilCollected)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iScoreFromDistance = ", sIAPData.sScoreTracking.iScoreFromDistance)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iScoreFromLives = ", sIAPData.sScoreTracking.iScoreFromLives)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] iScoreFromArmour = ", sIAPData.sScoreTracking.iScoreFromArmour)
//Debug
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] ----- DEBUG VALUES -----")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] bDrawCollisionDebug = ", sIAPData.sDebugStruct.bDrawCollisionDebug)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] bNoDamage = ", sIAPData.sDebugStruct.bNoDamage)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] bDontFailWhenOutOfLives = ", sIAPData.sDebugStruct.bDontFailWhenOutOfLives)
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] bDontReplenishLivesEachStage = ", sIAPData.sDebugStruct.bDontReplenishLivesEachStage)
ENDPROC
/// PURPOSE:
/// Updates all debug functionality for the minigame.
PROC IAP_DEBUG_PROCESSING()
IAP_DEBUG_CREATE_WIDGETS()
ARCADE_GAMES_POSTFX_WIDGET_UPDATE()
//Enable debug lines for collision debug
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
//Clamp Stage Speed
IF sIAPData.fStageSpeedMod > cfIAP_MAX_STAGE_SPEED_MOD
sIAPData.fStageSpeedMod = cfIAP_MAX_STAGE_SPEED_MOD
ENDIF
//Weapon Swaps
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_1, KEYBOARD_MODIFIER_NONE, "Swap to default weapon")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG WEAPON SWAP - IAP_PLAYER_WEAPON_DEFAULT")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_DEFAULT)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_2, KEYBOARD_MODIFIER_NONE, "Swap to flamethrower")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG WEAPON SWAP - IAP_PLAYER_WEAPON_FLAMETHROWER")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_FLAMETHROWER)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_3, KEYBOARD_MODIFIER_NONE, "Swap to rocket launcher")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG WEAPON SWAP - IAP_PLAYER_WEAPON_ROCKET_LAUNCHER")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_ROCKET_LAUNCHER)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_4, KEYBOARD_MODIFIER_NONE, "Swap to plasma cannon")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG WEAPON SWAP - IAP_PLAYER_WEAPON_PLASMA")
IAP_SET_PLAYER_WEAPON_TYPE(IAP_PLAYER_WEAPON_PLASMA)
ENDIF
//Stage Skipping
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_1, KEYBOARD_MODIFIER_CTRL, "Select Stage 0")
IAP_DEBUG_SKIP_TO_STAGE(IAP_STAGE_IRAQ)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_2, KEYBOARD_MODIFIER_CTRL, "Select Stage 1")
IAP_DEBUG_SKIP_TO_STAGE(IAP_STAGE_RUSSIA)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_3, KEYBOARD_MODIFIER_CTRL, "Select Stage 2")
IAP_DEBUG_SKIP_TO_STAGE(IAP_STAGE_CHINA)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_4, KEYBOARD_MODIFIER_CTRL, "Select Stage 3")
IAP_DEBUG_SKIP_TO_STAGE(IAP_STAGE_CANADA)
ENDIF
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_5, KEYBOARD_MODIFIER_CTRL, "Select Stage 4")
IAP_DEBUG_SKIP_TO_STAGE(IAP_STAGE_MOON)
ENDIF
//SCORE
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_PLUS, KEYBOARD_MODIFIER_CTRL, "+ Score")
IAP_ADD_SCORE(500000, IAP_SCORE_TYPE_OIL, INIT_VECTOR_2D(cfSCREEN_CENTER, cfSCREEN_CENTER))
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG SCORE")
sIAPData.iScoreToShow = IAP_GET_CURRENT_SCORE()
ENDIF
//CHALLENGES
IF sIAPData.sDebugStruct.bEnableAllChallenges
IAP_ENABLE_ALL_CHALLENGES(TRUE)
sIAPData.sDebugStruct.bEnableAllChallenges = FALSE
ENDIF
IF sIAPData.sDebugStruct.bDisableAllChallenges
IAP_ENABLE_ALL_CHALLENGES(FALSE)
sIAPData.sDebugStruct.bDisableAllChallenges = FALSE
ENDIF
IF sIAPData.sDebugStruct.bTriggerChallenge0
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - TRIGGER CHALLENGE 0")
IAP_UPDATE_KILL_CHALLENGE(TRUE)
sIAPData.sDebugStruct.bTriggerChallenge0 = FALSE
ENDIF
IF sIAPData.sDebugStruct.bTriggerChallenge1
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - TRIGGER CHALLENGE 1")
IAP_UPDATE_OIL_CHALLENGE(TRUE)
sIAPData.sDebugStruct.bTriggerChallenge1 = FALSE
ENDIF
IF sIAPData.sDebugStruct.bTriggerChallenge2
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - TRIGGER CHALLENGE 2")
IAP_UPDATE_MAX_MOON_DISTANCE(TRUE)
sIAPData.sDebugStruct.bTriggerChallenge2 = FALSE
ENDIF
IF sIAPData.sDebugStruct.bTriggerChallenge3
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - TRIGGER CHALLENGE 3")
IAP_UPDATE_LIVES_CHALLENGE(TRUE)
sIAPData.sDebugStruct.bTriggerChallenge3 = FALSE
ENDIF
IF sIAPData.sDebugStruct.bTriggerChallenge4
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - TRIGGER CHALLENGE 4")
IAP_UPDATE_SCORE_CHALLENGE(TRUE)
sIAPData.sDebugStruct.bTriggerChallenge4 = FALSE
ENDIF
//NUKE
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_N, KEYBOARD_MODIFIER_NONE, "NUKE")
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG NUKE")
IAP_NUKE_SCREEN()
ENDIF
//Debug pause
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_P, KEYBOARD_MODIFIER_NONE, "Pause Game")
sIAPData.sDebugStruct.bDebugPause = !sIAPData.sDebugStruct.bDebugPause
IF sIAPData.sDebugStruct.bDebugPause
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG PAUSE - PAUSED")
ELSE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG PAUSE - RESUMED")
ENDIF
ENDIF
IF sIAPData.sDebugStruct.bDebugPause
SET_TEXT_SCALE(1, 1)
SET_TEXT_COLOUR(255, 255, 255, 255)
SET_TEXT_CENTRE(TRUE)
SET_TEXT_FONT(FONT_STANDARD)
BEGIN_TEXT_COMMAND_DISPLAY_TEXT("STRING")
ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME("ARCADE GAME PAUSED - PRESS 'P' ON DEBUG KEYBOARD TO RESUME")
END_TEXT_COMMAND_DISPLAY_TEXT(cfSCREEN_CENTER, cfSCREEN_CENTER)
ENDIF
//If a bug is entered dump all data to the console.
IF IS_KEYBOARD_KEY_PRESSED(KEY_SPACE)
OR IS_KEYBOARD_KEY_PRESSED(KEY_RBRACKET)
sIAPData.sDebugStruct.bDebugPause = TRUE
CDEBUG1LN(DEBUG_MINIGAME, "[IAP] [JS] IAP_DEBUG_PROCESSING - DEBUG PAUSE - PAUSED")
IAP_DEBUG_DUMP_DATA_TO_LOGS()
ENDIF
ENDPROC
#ENDIF
// ------------------------------ EVENT PROCESSING ------------------------------
/// PURPOSE:
/// Processes all incoming events
PROC IAP_PROCESS_EVENTS()
//REMOVE IF ANY OTHER EVENTS ADDED
IF sIAPData.bLeaderboardRecieved
EXIT
ENDIF
INT iCount
SCRIPT_EVENT_DATA_CASINO_ARCADE_SEND_LEADERBOARD_EVENT EventDataLeaderboardSend
REPEAT GET_NUMBER_OF_EVENTS(SCRIPT_EVENT_QUEUE_NETWORK) iCount
IF GET_EVENT_AT_INDEX(SCRIPT_EVENT_QUEUE_NETWORK, iCount) != EVENT_NETWORK_SCRIPT_EVENT
RELOOP
ENDIF
IF GET_EVENT_DATA(SCRIPT_EVENT_QUEUE_NETWORK, iCount, EventDataLeaderboardSend, SIZE_OF(EventDataLeaderboardSend))
IF EventDataLeaderboardSend.Details.Type = SCRIPT_EVENT_CASINO_ARCADE_SEND_LEADERBOARD_EVENT
IF EventDataLeaderboardSend.eGameType != CASINO_ARCADE_GAME_INVADE_PERSUADE
RELOOP
ENDIF
IAP_INITIALISE_LEADERBOARD(EventDataLeaderboardSend.iInitials, EventDataLeaderboardSend.iScores)
RELOOP
ENDIF
ENDIF
ENDREPEAT
ENDPROC
// ------------------------------ MAIN UPDATE ------------------------------
/// PURPOSE:
/// Run every frame before the client state machine is processed
PROC IAP_PRE_UPDATE()
IF sIAPData.eCurrentState >= IAP_CLIENT_STATE_CLEANUP
// Cleaning up, don't do anything
EXIT
ENDIF
IF NOT IS_SKYSWOOP_AT_GROUND()
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_CLEANUP)
EXIT
ENDIF
IF IAP_SHOULD_QUIT_NOW()
IF IS_PLAYER_IN_ARCADE_PROPERTY(PLAYER_ID())
sIAPData.sArcadeCabinetAnimEvent.bLoopAnim = FALSE
sIAPData.sArcadeCabinetAnimEvent.bHoldLastFrame = FALSE
PLAY_ARCADE_CABINET_ANIMATION(sIAPData.sArcadeCabinetAnimEvent, ARCADE_CABINET_ANIM_CLIP_EXIT)
ENDIF
IAP_SET_CLIENT_STATE(IAP_CLIENT_STATE_CLEANUP)
EXIT
ENDIF
IAP_PROCESS_EVENTS()
IF NOT sIAPData.bLeaderboardRecieved
AND (sIAPData.iLastLeaderboardRequest = -HIGHEST_INT
OR NATIVE_TO_INT(GET_NETWORK_TIME()) - sIAPData.iLastLeaderboardRequest > ciIAP_RESEND_LEADERBOARD_REQUEST_TIME)
BROADCAST_CASINO_ARCADE_REQUEST_LEADERBOARD_EVENT(GET_OWNER_OF_SIMPLE_INTERIOR_PLAYER_IS_IN(PLAYER_ID()), CASINO_ARCADE_GAME_INVADE_PERSUADE)
sIAPData.iLastLeaderboardRequest = NATIVE_TO_INT(GET_NETWORK_TIME())
ENDIF
IAP_UPDATE_ANIM_FRAMES()
//Reset help text bit
CLEAR_BIT(sIAPData.sPlayerTank.iPlayerTankBitset, ciIAP_PLAYER_TANK_BS_SHOWING_HELP_TEXT)
BOOL bIsPlaying = sIAPData.eCurrentState >= IAP_CLIENT_STATE_DEGENETRON
ARCADE_CABINET_COMMON_EVERY_FRAME_PROCESSING(bIsPlaying)
ENDPROC
/// PURPOSE:
/// Run every frame after the client state machine is processed
PROC IAP_POST_UPDATE()
IF NOT IAP_SHOULD_ALLOW_HELP_TEXT_THIS_FRAME()
HIDE_HELP_TEXT_THIS_FRAME()
ENDIF
sIAPData.sPlayerTank.iLastFrameTurretDirection = sIAPData.sPlayerTank.iTurretDirection
ENDPROC
/// PURPOSE:
/// Call every frame to run the minigame
PROC PROCESS_INVADE_AND_PERSUADE()
IAP_PRE_UPDATE()
#IF IS_DEBUG_BUILD
IF NOT sIAPData.sDebugStruct.bDebugPause
#ENDIF
IAP_PROCESS_CLIENT_STATE_MACHINE()
#IF IS_DEBUG_BUILD
ENDIF
#ENDIF
IAP_POST_UPDATE()
#IF IS_DEBUG_BUILD
IAP_DEBUG_PROCESSING()
#ENDIF
ENDPROC