aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/scripts/vscripts/ai/_ai_nuke_titans.gnut
blob: 0d4b43c92a6e82800b5ec435eebdf758fe3a331f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
untyped

global function NukeTitanThink

global function AutoTitan_SelfDestruct

const NUKE_TITAN_PLAYER_DETECT_RANGE 	= 500
const NUKE_TITAN_RANGE_CHECK_SLEEP_SECS = 1.0

void function AutoTitan_SelfDestruct( entity titan )
{
	if ( titan.ContextAction_IsBusy() )
		titan.ContextAction_ClearBusy()

	thread TitanEjectPlayer( titan )
}

void function NukeTitanThink( entity titan, entity generator )
{
	//Function assumes that given Titan is spawned as npc_titan_ogre_meteor_nuke. Changing the Titan's AISettings post-spawn
	//disrupts the Titan's titanfall animations and can result in the Titan landing outside the level.
	NPC_SetNuclearPayload( titan )
	AddEntityCallback_OnPostDamaged( titan, AutoTitan_NuclearPayload_PostDamageCallback )

	WaitTillHotDropComplete( titan )

	thread NukeTitanSeekOutGenerator( titan, generator )
}


void function NukeTitanSeekOutGenerator( entity titan, entity generator )
{
	titan.EndSignal( "OnDeath" )
	titan.EndSignal( "OnDestroy" )
	titan.EndSignal( "Doomed" )

	WaitSignal( titan, "FD_ReachedHarvester", "OnFailedToPath" )

	float goalRadius = 100
	float checkRadiusSqr = 400 * 400

	//array<vector> pos = NavMesh_RandomPositions( generator.GetOrigin(), HULL_TITAN, 5, 250, 350 )
	array<vector> pos = NavMesh_GetNeighborPositions( generator.GetOrigin(), HULL_TITAN, 5 )
	pos = ArrayClosestVector( pos, titan.GetOrigin() )

	array<vector> validPos
	foreach ( point in pos )
	{
		if ( DistanceSqr( generator.GetOrigin(), point ) <= checkRadiusSqr && NavMesh_IsPosReachableForAI( titan, point ) )
		{
			validPos.append( point )
			//DebugDrawSphere( point, 32, 255, 0, 0, true, 60 )
		}
	}

	int posLen = validPos.len()
	while( posLen >= 1 )
	{
		titan.SetEnemy( generator )
		thread AssaultOrigin( titan, validPos[0], goalRadius )
		titan.AssaultSetFightRadius( goalRadius )

		wait 0.5

		if ( DistanceSqr( titan.GetOrigin(), generator.GetOrigin() ) > checkRadiusSqr )
			continue

		break
	}

	thread AutoTitan_SelfDestruct( titan )
}

// intercept damage to nuke titans in damage callback so we can nuke them before death 100% of the time
void function AutoTitan_NuclearPayload_PostDamageCallback( entity titan, var damageInfo )
{
	if ( !IsAlive( titan ) )
		return

	entity titanOwner = titan.GetBossPlayer()
	if ( IsValid( titanOwner ) )
	{
		Assert( titanOwner.IsPlayer() )
		Assert( GetPlayerTitanInMap( titanOwner ) == titan )
		return
	}

	int nuclearPayload = NPC_GetNuclearPayload( titan )
	if ( nuclearPayload == 0 )
		return

	if ( !GetDoomedState( titan ) )
		return

	if ( titan.GetTitanSoul().IsEjecting() )
		return

	// Nuke eject as soon as the titan enters doom state.
	if ( !( "doomedStateNukeTriggerHealth" in titan.s ) )
	{
		titan.s.doomedStateNukeTriggerHealth <- titan.GetMaxHealth()
	}

	if ( titan.GetHealth() > titan.s.doomedStateNukeTriggerHealth )
	{
		//printt( "titan health:", titan.GetHealth(), "health to nuke:", titan.s.doomedStateNukeTriggerHealth )
		return
	}

	printt( "NUKE TITAN DOOMED TRIGGER HEALTH REACHED, NUKING! Health:", titan.s.doomedStateNukeTriggerHealth )

	thread AutoTitan_SelfDestruct( titan )
}

function AutoTitan_CanDoRangeCheck( autoTitan )
{
	if ( !( "nextPlayerTitanRangeCheckTime" in autoTitan.s ) )
		autoTitan.s.nextPlayerTitanRangeCheckTime <- -1

	if ( Time() < autoTitan.s.nextPlayerTitanRangeCheckTime )
	{
		return false
	}
	else
	{
		autoTitan.s.nextPlayerTitanRangeCheckTime = Time() + NUKE_TITAN_RANGE_CHECK_SLEEP_SECS
		return true
	}
}