forked from beginnerToSourceSDK/SWATEliteForce
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAttackEnemyAction.uc
160 lines (125 loc) · 4.32 KB
/
AttackEnemyAction.uc
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
///////////////////////////////////////////////////////////////////////////////
// AttackEnemyAction.uc - AttackEnemyAction class
// The action that causes the AI to attack a particular enemy with any weapon it
// has
class AttackEnemyAction extends SwatCharacterAction;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Variables
var(parameters) Pawn Enemy;
///////////////////////////////////////////////////////////////////////////////
//
// AttackEnemyAction variables
// behaviors we use
var protected MoveOfficerToEngageGoal CurrentMoveOfficerToEngageGoal;
var protected AttackTargetGoal CurrentAttackTargetGoal;
// constants
const kMinAttackEnemyUpdateTime = 0.1;
const kMaxAttackEnemyUpdateTime = 0.25;
///////////////////////////////////////////////////////////////////////////////
//
// Selection Heuristic
function float selectionHeuristic( AI_Goal goal )
{
return FRand();
}
function Pawn GetEnemy()
{
// If this behavior was created for a specific enemy target, return that enemy.
if (Enemy != None)
return Enemy;
return ISwatOfficer(m_Pawn).GetOfficerCommanderAction().GetCurrentAssignment();
}
///////////////////////////////////////////////////////////////////////////////
//
// Init / Cleanup
function cleanup()
{
super.cleanup();
if (CurrentMoveOfficerToEngageGoal != None)
{
CurrentMoveOfficerToEngageGoal.Release();
CurrentMoveOfficerToEngageGoal = None;
}
if (CurrentAttackTargetGoal != None)
{
CurrentAttackTargetGoal.Release();
CurrentAttackTargetGoal = None;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Sub-Behavior Messages
function goalNotAchievedCB( AI_Goal goal, AI_Action child, ACT_ErrorCodes errorCode )
{
super.goalNotAchievedCB(goal, child, errorCode);
if ((goal == CurrentAttackTargetGoal) || (goal == CurrentMoveOfficerToEngageGoal))
{
// if the attacking or movement fails, we succeed so we don't get reposted,
// the OfficerCommanderAction will figure out what to do
InstantSucceed();
}
}
///////////////////////////////////////////////////////////////////////////////
//
// State Code
// we only move to attack the enemy if we should
// (not in the middle of executing a move and clear!)
function bool ShouldMoveToAttackEnemy()
{
local SwatAIRepository SwatAIRepo;
SwatAIRepo = SwatAIRepository(Level.AIRepo);
// test to see if we're moving and clearing
return (! SwatAIRepo.IsOfficerMovingAndClearing(m_Pawn));
}
// returns true if we're moving and clearing, or if our move to engage goal hasn't completed
// returns false otherwise
function bool IsMovingToAttack()
{
return (!ShouldMoveToAttackEnemy() || ((CurrentMoveOfficerToEngageGoal != None) && !CurrentMoveOfficerToEngageGoal.hasCompleted()));
}
private function MoveToAttackEnemy()
{
// only move to attack the enemy if we should
if (m_Pawn.logAI)
log(m_Pawn.Name $ " will move to attack the enemy");
CurrentMoveOfficerToEngageGoal = new class'MoveOfficerToEngageGoal'(movementResource(), achievingGoal.Priority, GetEnemy());
assert(CurrentMoveOfficerToEngageGoal != None);
CurrentMoveOfficerToEngageGoal.AddRef();
CurrentMoveOfficerToEngageGoal.SetRotateTowardsPointsDuringMovement(true);
// post the move to goal
CurrentMoveOfficerToEngageGoal.postGoal(self);
}
private function AttackEnemyWithWeapon()
{
CurrentAttackTargetGoal = new class'AttackTargetGoal'(weaponResource(), GetEnemy());
assert(CurrentAttackTargetGoal != None);
CurrentAttackTargetGoal.AddRef();
// post the attack target goal
CurrentAttackTargetGoal.postGoal(self);
}
state Running
{
Begin:
waitForResourcesAvailable(achievingGoal.priority, achievingGoal.priority);
AttackEnemyWithWeapon();
// while the attacking goal hasn't completed
while (! CurrentAttackTargetGoal.hasCompleted())
{
// if we aren't moving the officer to engage (if we were moving and clearing)
// try to move to attack the enemy
if ((CurrentMoveOfficerToEngageGoal == None) && ShouldMoveToAttackEnemy())
{
MoveToAttackEnemy();
}
sleep(RandRange(kMinAttackEnemyUpdateTime, kMaxAttackEnemyUpdateTime));
}
// enemy must be dead
succeed();
}
///////////////////////////////////////////////////////////////////////////////
defaultproperties
{
satisfiesGoal = class'AttackEnemyGoal'
}