‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
behavior_state_machine.gsc
Go to the documentation of this file.
1 // Created and Implemented by Sumeet Jakatdar
2 #insert scripts\shared\shared.gsh;
3 #insert scripts\shared\ai\systems\behavior_state_machine.gsh;
4 
5 #define NULL 0
6 #define IS_NULL(variable) (IsInt(variable) && variable == 0)
7 
8 #namespace BehaviorStateMachine;
9 
10 // ------------- Behavior State Machine Script API registration ----------- //
11 function ‪RegisterBSMScriptAPIInternal( functionName, scriptFunction )
12 {
13  if ( !IsDefined( level._bsmscriptfunctions ) )
14  {
15  level._bsmscriptfunctions = [];
16  }
17 
18  // SUMEET TODO - remove the need of ToLower and have the functionNames defined in .gsh
19  functionName = ToLower( functionName );
20 
21  Assert( IsDefined( scriptFunction ) && IsDefined( scriptFunction ), "BT - (RegisterBSMScriptAPI) No functionPtr defined or no functionName defined for BSMScript." );
22  Assert( !IsDefined( level._bsmscriptfunctions[functionName] ), "BT - (RegisterBSMScriptAPI) functionName is already defined for BSMScript." );
23 
24  level._bsmscriptfunctions[functionName] = scriptFunction;
25 }
26 
27 /*
28 
29 class BehaviorState
30 {
31  var stateName;
32 
33  var asmStateName;
34 
35  var initFunc;
36  var updateFunc;
37  var terminateFunc;
38 
39  var connections;
40 
41  constructor()
42  {
43  connections = [];
44  }
45 
46  destructor()
47  {
48 
49  }
50 
51  function GetConnections()
52  {
53  return connections;
54  }
55 }
56 
57 class BehaviorConnection
58 {
59  var connectionName;
60  var toState;
61  var conditionFunc;
62  var endOfStateConnection;
63 
64  var asmState;
65 
66  constructor()
67  {
68  toState = NULL;
69  }
70 
71  destructor()
72  {
73 
74  }
75 }
76 
77 class BSM
78 {
79  var stateMachineName;
80  var states;
81  var miscData;
82 
83  var currentState;
84  var previousState;
85 
86  constructor()
87  {
88  states = [];
89  }
90 
91  destructor()
92  {
93 
94  }
95 
96  function AddState( stateName, asmStateName, initFunc, updateFunc, terminateFunc )
97  {
98  assert( !IsDefined( states[stateName] ), "BSM - State is already defined " + stateName );
99 
100  states[stateName] = new BehaviorState();
101 
102  states[stateName].initFunc = initFunc;
103  states[stateName].updateFunc = updateFunc;
104  states[stateName].terminateFunc = terminateFunc;
105 
106  states[stateName].asmStateName = asmStateName;
107  states[stateName].stateName = stateName;
108  }
109 
110  function AddConnection( connectionName, fromState, toState, conditionFunc, endOfStateConnection, asmState )
111  {
112  assert( IsDefined( states[fromState] ), "BSM - State is not defined " + fromState );
113  assert( IsDefined( states[toState] ), "BSM - State is not defined " + toState );
114  assert( !IsDefined( states[fromState].connections[connectionName] ), "BSM - Connection is already defined " + connectionName );
115 
116  states[fromState].connections[connectionName] = new BehaviorConnection();
117 
118  states[fromState].connections[connectionName].toState = toState;
119  states[fromState].connections[connectionName].conditionFunc = conditionFunc;
120  states[fromState].connections[connectionName].connectionName = connectionName;
121  states[fromState].connections[connectionName].endOfStateConnection = endOfStateConnection;
122 
123  states[fromState].connections[connectionName].asmState = asmState;
124  }
125 
126  function GetStates()
127  {
128  return states;
129  }
130 }
131 
132 function CreateBSM( archetypeName, stateMachineName )
133 {
134  if( !IsDefined( level.__BSMs ) )
135  {
136  level.__BSMs = [];
137  }
138 
139  if( !IsDefined( level.__BSMs[archetypeName] ) )
140  {
141  level.__BSMs[archetypeName] = [];
142  }
143 
144  assert( !IsDefined( level.__BSMs[archetypeName][stateMachineName] ) );
145 
146  newStateMachine = new BSM();
147  newStateMachine.stateMachineName = stateMachineName;
148 
149  level.__BSMs[archetypeName][stateMachineName] = newStateMachine;
150 
151  return level.__BSMs[archetypeName][stateMachineName];
152 }
153 
154 function StartBSM( entity, stateMachineName )
155 {
156  assert( IsDefined( level.__BSMs[entity.archetype][stateMachineName] ) );
157 
158  stateMachine = level.__BSMs[entity.archetype][stateMachineName];
159 
160  assert( !IsDefined( stateMachine.currentState ) );
161  assert( !IsDefined( stateMachine.previousState ) );
162 
163  // go through the states, find the first fit
164  foreach ( state in stateMachine.states )
165  {
166  if( !IsDefined( state.initFunc ) )
167  {
168  if( IsDefined( state.asmStateName ) )
169  {
170  newState = state;
171  break;
172  }
173  }
174  else
175  {
176  validState = [[state.initFunc]]( entity );
177 
178  if( validState )
179  {
180  // found one state which has a valid ASM, set it as a current substate
181  if( IsDefined( state.asmStateName ) )
182  {
183  newState = state;
184  break;
185  }
186  }
187  }
188  }
189 
190  if( IsDefined( newState ) )
191  {
192  stateMachine.currentState = newState;
193  AnimationStateNetworkUtility::RequestState( entity, newState.asmStateName );
194  return BHTN_RUNNING;
195  }
196 
197  return BHTN_SUCCESS;
198 }
199 
200 function UpdateBSM( entity, stateMachineName )
201 {
202  assert( IsDefined( level.__BSMs[entity.archetype][stateMachineName] ) );
203 
204  stateMachine = level.__BSMs[entity.archetype][stateMachineName];
205 
206  assert( IsDefined( stateMachine.currentState ) );
207 
208  // run the update function for the current state
209  currentStateUpdatedResult = true;
210  if( IsDefined( stateMachine.currentState.updateFunc ) )
211  {
212  currentStateUpdatedResult = [[stateMachine.currentState.updateFunc]]( entity );
213  }
214 
215  // We have a valid running state, go through all the connections ( if there are any )
216  connections = [[stateMachine.currentState]]->GetConnections();
217 
218  if( !connections.size )
219  {
220  if( entity ASMGetStatus() == ASM_STATE_COMPLETE )
221  {
222  TerminateBSM( entity, stateMachineName );
223  return BHTN_SUCCESS;
224  }
225  }
226  else
227  {
228  nextValidState = undefined;
229 
230  foreach ( connection in connections )
231  {
232  // execute endOfStateConnection only when current state is complete or is not valid anymore
233  if( IS_TRUE( connection.endOfStateConnection )
234  && ( entity ASMGetStatus() != ASM_STATE_COMPLETE || !currentStateUpdatedResult )
235  )
236  {
237  /#RecordEntText( "EndOfStateConnection :" + connection.connectionName, entity, RED, "Animscript" );#/
238  continue;
239  }
240 
241  if( IsDefined( connection.conditionFunc ) )
242  {
243  // check if the connection is valid
244  validConnection = [[connection.conditionFunc]]( entity );
245 
246  if( !IsDefined( validConnection ) )
247  validConnection = true;
248 
249  // Connection is valid, check if the toState has any condition associated with it, and execute it
250  if( validConnection )
251  {
252  /#RecordEntText( "Connection :" + connection.connectionName, entity, GREEN, "Animscript" );#/
253 
254  if( !IsDefined( stateMachine.states[connection.toState].initFunc ) )
255  {
256  nextValidState = stateMachine.states[connection.toState];
257  break;
258  }
259  else
260  {
261  validToState = [[stateMachine.states[connection.toState].initFunc]]( entity );
262 
263  if( validToState )
264  {
265  nextValidState = stateMachine.states[connection.toState];
266  break;
267  }
268  else
269  {
270  /#RecordEntText( "ToState :" + stateMachine.states[connection.toState].stateName, entity, RED, "Animscript" );#/
271  }
272  }
273  }
274  else
275  {
276  /#RecordEntText( "Connection :" + connection.connectionName, entity, RED, "Animscript" );#/
277  }
278  }
279  else
280  {
281  /#RecordEntText( "Connection :" + connection.connectionName, entity, GREEN, "Animscript" );#/
282 
283  if( !IsDefined( stateMachine.states[connection.toState].initFunc ) )
284  {
285  nextValidState = stateMachine.states[connection.toState];
286  break;
287  }
288  else
289  {
290  validToState = [[stateMachine.states[connection.toState].initFunc]]( entity );
291 
292  if( validToState )
293  {
294  nextValidState = stateMachine.states[connection.toState];
295  break;
296  }
297  else
298  {
299  /#RecordEntText( "ToState :" + stateMachine.states[connection.toState].stateName, entity, RED, "Animscript" );#/
300  }
301  }
302  }
303  }
304 
305  // found a validNextState with ValidConnection, go there now
306  if( IsDefined( nextValidState ) )
307  {
308  // found a new valid state, execute terminateFunc of the current state
309  if( IsDefined( stateMachine.currentState.terminateFunc ) )
310  {
311  [[stateMachine.currentState.terminateFunc]]( entity );
312  }
313 
314  /#RecordEntText( "ToState :" + stateMachine.states[connection.toState].stateName, entity, GREEN, "Animscript" );#/
315 
316  stateMachine.previousState = stateMachine.currentState;
317  stateMachine.currentState = nextValidState;
318 
319  assert( IsDefined( nextValidState.asmStateName ) );
320 
321  AnimationStateNetworkUtility::RequestState( entity, nextValidState.asmStateName );
322 
323  return BHTN_RUNNING;
324  }
325  else
326  {
327  /#RecordEntText( "ToState :" + stateMachine.states[connection.toState].stateName, entity, RED, "Animscript" );#/
328  }
329  }
330 
331  // if there is no better connection, just update the current substate
332  if( entity ASMGetStatus() == ASM_STATE_COMPLETE )
333  {
334  TerminateBSM( entity, stateMachineName );
335  return BHTN_SUCCESS;
336  }
337  else
338  {
339  /#RecordEntText( "CurrentState :" + stateMachine.currentState.stateName, entity, BLUE, "Animscript" );#/
340  }
341 
342  return BHTN_RUNNING;
343 }
344 
345 function TerminateBSM( entity, stateMachineName )
346 {
347  assert( IsDefined( level.__BSMs[entity.archetype][stateMachineName] ) );
348 
349  stateMachine = level.__BSMs[entity.archetype][stateMachineName];
350 
351  // state machine is terminating and returning control to behavior tree, call terminateFunc of the current state
352  if( IsDefined( stateMachine.currentState ) && IsDefined( stateMachine.currentState.terminateFunc ) )
353  {
354  [[stateMachine.currentState.terminateFunc]]( entity );
355  }
356 
357  stateMachine.currentState = undefined;
358  stateMachine.previousState = undefined;
359 
360  return BHTN_SUCCESS;
361 }
362 
363 */
‪RegisterBSMScriptAPIInternal
‪function RegisterBSMScriptAPIInternal(functionName, scriptFunction)
Definition: behavior_state_machine.gsc:11