Files
gtav-src/script/dev_ng/singleplayer/scripts/Minigames/Darts/Darts_AI.sch
T
2025-09-29 00:52:08 +02:00

282 lines
9.8 KiB
XML
Executable File

////////////////////////////////////////////////////////////////////
// //
// SCRIPT NAME : Darts_AI.sch //
// AUTHOR : Lino Manansala //
// DESCRIPTION : AI Dart Throws //
// //
//////////////////////////////////////////////////////////////
USING "Darts_Dart_lib.sch"
USING "Darts_Board.sch"
ENUM DARTS_DIFFICULTY
DARTSDIFF_NORMAL = 0,
DARTSDIFF_HARD,
DARTSDIFF_VERY_HARD
ENDENUM
STRUCT DARTS_AI_BRAIN
INT iThrowValue
INT iThrowMultiplier
INT iScoreDifference
INT iThrowTotal
DARTS_DIFFICULTY eDifficulty
ENDSTRUCT
FUNC INT GET_ACCURACY_LOWER_LIMIT(DARTS_AI_BRAIN & DartsAIBrain)
SWITCH DartsAIBrain.eDifficulty
CASE DARTSDIFF_NORMAL RETURN 25
CASE DARTSDIFF_HARD RETURN 75
CASE DARTSDIFF_VERY_HARD RETURN 90
DEFAULT RETURN 25
ENDSWITCH
ENDFUNC
PROC GET_NEXT_AI_THROW(INT & iScore[], DARTS_AI_BRAIN & DartsAIBrain) //INT & DartsAIBrain.iThrowValue, INT & DartsAIBrain.iThrowMultiplier)
INT i
DartsAIBrain.iThrowValue = 0
DartsAIBrain.iThrowMultiplier = 0
DartsAIBrain.iScoreDifference = iScore[1] - iScore[0]
DartsAIBrain.iThrowTotal++
// Still got a big score... so just go for those treble 20s!
IF iScore[iPlayr] > 121//110
DartsAIBrain.iThrowValue = 20
DartsAIBrain.iThrowMultiplier = 3
ELIF iScore[iPlayr] > 60
// Now we're getting low, go for the treble 19 to cancel out our remainder
IF iScore[iPlayr] % 2 = 1
IF GET_RANDOM_BOOL()
DartsAIBrain.iThrowValue = 19
ELSE
DartsAIBrain.iThrowValue = 17
ENDIF
DartsAIBrain.iThrowMultiplier = 3
ELSE
DartsAIBrain.iThrowValue = 20
DartsAIBrain.iThrowMultiplier = 3
ENDIF
ELIF iScore[iPlayr] < 61
// we can checkout on the bull, go for this for style... it won't happen often
IF iScore[iPlayr] = 50
DartsAIBrain.iThrowValue = 50
DartsAIBrain.iThrowMultiplier = 1
// hit a single to take our score down to 40,
// then checkout on double 20
ELIF iScore[iPlayr] > 52
DartsAIBrain.iThrowValue = iScore[iPlayr] - 40
DartsAIBrain.iThrowMultiplier = 1
// hit a single to take our score down to 32,
// then checkout on double 16
ELIF iScore[iPlayr] > 40
DartsAIBrain.iThrowValue = iScore[iPlayr] - 32
DartsAIBrain.iThrowMultiplier = 1
// our score is 40 or less
ELSE
// check to see if we can checkout on 1 dart...
// if score is even, check us out
IF iScore[iPlayr] % 2 = 0
i=1
REPEAT 20 i
DartsAIBrain.iThrowValue = iScore[iPlayr] / 2
DartsAIBrain.iThrowMultiplier = 2
ENDREPEAT
// we weren't able to 1 dart checkout, we've got an odd number
ELSE
// find the best 2 dart checkout from double 16 down to double 1
i = 32
WHILE DartsAIBrain.iThrowValue = 0 AND i > 1
IF iScore[iPlayr] > i
DartsAIBrain.iThrowValue = iScore[iPlayr] - i
DartsAIBrain.iThrowMultiplier = 1
ENDIF
i /= 2
ENDWHILE
ENDIF
ENDIF
ENDIF
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW] Pre-vector, DartsAIBrain.iThrowValue = ", DartsAIBrain.iThrowValue)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW] Pre-vector, DartsAIBrain.iThrowMultiplier = ", DartsAIBrain.iThrowMultiplier)
ENDPROC
PROC GET_AI_THROW_VECTOR(DART & Darts, DARTS_BOARD & DartsBoard, DARTS_PLAYER_STATE & turnStage, DARTS_AI_BRAIN & DartsAIBrain, BOOL bIsTutorial = FALSE)
FLOAT fTempAI
FLOAT fTemp1, fTemp2
FLOAT fAIThrowLength
FLOAT fAIThrowAngle
INT i
INT iOpponentShotAccuracy
VECTOR vTemp2, vTemp3
// Find out if the dart has landed in the bull, outer bull or out of the score zone
IF DartsAIBrain.iThrowValue = 50 // bull
fAIThrowLength = 0.0
fAIThrowAngle = GET_RANDOM_FLOAT_IN_RANGE(0.0, 360.0)
ELIF DartsAIBrain.iThrowValue = 25 // outer bull
fAIThrowLength = 0.14
fAIThrowAngle = GET_RANDOM_FLOAT_IN_RANGE(0.0, 360.0)
// The dart is being aimed at a number
ELSE
// Set the length of the vector (treble, double, single)
IF DartsAIBrain.iThrowMultiplier = 3
fAIThrowLength = 0.1345
// fAIThrowLength = 0.131
ELIF DartsAIBrain.iThrowMultiplier = 2
fAIThrowLength = 0.218
// fAIThrowLength = 0.208
ELSE
fAIThrowLength = 0.180
ENDIF
// Set the angle of the vector (the number it's aimed at)
FLOAT fDartAngleIncremented =0.0
i=0
REPEAT 21 i
IF DartsAIBrain.iThrowValue = iScoreForSection[i]
fAIThrowAngle = fDartAngleIncremented
ENDIF
fDartAngleIncremented += 18.0
ENDREPEAT
ENDIF
IF NOT bIsTutorial AND DartsAIbrain.iThrowTotal < 30
// TODO: ADJUST DIFFICULTY HERE. FACTOR IN FRIEND ACTIVITY, AND PLAYER'S WINNING PCT
// ************************************************************
// ******* Add randomness to the AI throw *********************
// ************************************************************
// ************************************************ ANGLE *****
i = GET_RANDOM_INT_IN_RANGE(0, 100)
iOpponentShotAccuracy = GET_RANDOM_INT_IN_RANGE(GET_ACCURACY_LOWER_LIMIT(DartsAIBrain), 150)
IF DartsAIBrain.iScoreDifference > 140 //Do a good shot if AI is way behind
ftempAI = GET_RANDOM_FLOAT_IN_RANGE(-35.0, 35.0) //(-50.0, 50.0)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS IN COMEBACK MODE")
ELIF i < iOpponentShotAccuracy AND DartsAIBrain.eDifficulty = DARTSDIFF_VERY_HARD
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-80.0, 80.0)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A VERY GOOD SHOT")
ELIF i < iOpponentShotAccuracy AND DartsAIBrain.iScoreDifference > -140 // Do a good shot! while computer is not too far ahead
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-60.0, 60.0)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A GOOD SHOT")
ELSE // Do a bad shot!
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-100.0, 100.0)
// Go left...
IF fTempAI > 0
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-200.0, -60.0)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A BAD SHOT LEFT")
// Go right...
ELSE
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(60.0, 200.0)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A BAD SHOT RIGHT")
ENDIF
ENDIF
fTempAI /= 10
fAIThrowAngle += fTempAI
// ************************************************ LENGTH *****
i = GET_RANDOM_INT_IN_RANGE(0, 100)
iOpponentShotAccuracy = GET_RANDOM_INT_IN_RANGE(GET_ACCURACY_LOWER_LIMIT(DartsAIBrain), 150)
IF DartsAIBrain.iScoreDifference > 140 //Do a good shot if AI is way behind
ftempAI = GET_RANDOM_FLOAT_IN_RANGE(-0.25, 0.25)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS IN COMEBACK MODE")
ELIF i < iOpponentShotAccuracy AND DartsAIBrain.eDifficulty = DARTSDIFF_VERY_HARD
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-0.07, 0.07)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A VERY GOOD SHOT")
ELIF i < iOpponentShotAccuracy AND DartsAIBrain.iScoreDifference > -140 // Do a good shot! while computer is not too far ahead
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-0.15, 0.15) //(-0.3, 0.3)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A GOOD SHOT")
ELSE // Do a bad shot!
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-100.0, 100.0)
// Go high...
IF fTempAI > 0
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(-1.0, -0.3)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A BAD SHOT HIGH")
// Go low...
ELSE
fTempAI = GET_RANDOM_FLOAT_IN_RANGE(0.3, 1.0)
CDEBUG1LN(DEBUG_DARTS, "[GET_NEXT_AI_THROW]********************* AI IS MAKING A BAD SHOT LOW")
ENDIF
ENDIF
fTempAI /= 10
fAIThrowLength += fTempAI
// ************************************************************
// **********************************************************
ENDIF
// offset to the proper center of the board
Darts.vTarget.x = SIN(fAIThrowAngle) * fAIThrowLength
Darts.vTarget.y = -0.23
Darts.vTarget.z = COS(fAIThrowAngle) * fAIThrowLength
Darts.vTarget.x -= 0.0035
Darts.vTarget.z -= 0.0002
IF turnStage = DPS_SKIP_AI
CDEBUG1LN(DEBUG_DARTS, "*******************************")
CDEBUG1LN(DEBUG_DARTS, "*AI Throw Length = ", fAIThrowLength)
CDEBUG1LN(DEBUG_DARTS, "*Darts vTarget = ", Darts.vTarget)
SET_DART_THROW_VECTOR(Darts)
CDEBUG1LN(DEBUG_DARTS, "*Darts vOffsetTarget = ", Darts.vOffsetTarget)
CDEBUG1LN(DEBUG_DARTS, "*******************************")
ELSE
Darts.bStuck = FALSE
Darts.bTravelling = TRUE
SET_DART_THROW_VECTOR(Darts)
// create the dart
Darts.object = CREATE_OBJECT(Darts.modelDart, vInitDartPos, FALSE, FALSE)
fTemp1 = GET_RANDOM_FLOAT_IN_RANGE(0.0, 90.0)
vTemp2 = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(DartsBoard.vDartBoard, DartsBoard.fBoardHeading,
vInitDartPosOffset)
vTemp3 = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(DartsBoard.vDartBoard, DartsBoard.fBoardHeading,
<< Darts.vTarget.x,
Darts.vTarget.y + fdartboardOriginOffset,
Darts.vTarget.z >>)
fTemp2 = GET_HEADING_FROM_VECTOR_2D((vTemp2.x - vTemp3.x), (vTemp2.y - vTemp3.y))
fTemp2 -= 180
Darts.vRotation = << 90, fTemp1, fTemp2>>
SET_ENTITY_ROTATION(Darts.object, Darts.vRotation, EULER_XYZ)
Darts.vPosition = vInitDartPosOffset // keep track of the dart's offset
turnStage = DPS_THROW
PLAY_SOUND_FROM_ENTITY(-1, "DARTS_THROW_DART_MASTER", Darts.object)
ENDIF
ENDPROC