1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "bladerunner/script/ai_script.h"
24 
25 namespace BladeRunner {
26 
AIScriptHowieLee(BladeRunnerEngine * vm)27 AIScriptHowieLee::AIScriptHowieLee(BladeRunnerEngine *vm) : AIScriptBase(vm) {
28 	var_45DFB8 = 0;
29 }
30 
Initialize()31 void AIScriptHowieLee::Initialize() {
32 	_animationFrame = 0;
33 	_animationState = 0;
34 	_animationStateNext = 0;
35 	_animationNext = 0;
36 	var_45DFB8 = false;
37 
38 	Actor_Put_In_Set(kActorHowieLee, kSetCT01_CT12);
39 	Actor_Set_At_Waypoint(kActorHowieLee, 67, 605); // in kSetCT01_CT12
40 	Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
41 }
42 
Update()43 bool AIScriptHowieLee::Update() {
44 
45 	if (_vm->_cutContent) {
46 		// keep Howie in Acts 2 and 3
47 		// Howie in Acts 2 and 3 will have a routine with existing waypoints/goals,
48 		// so no need to add new goals (> 100) for those Acts
49 		if (Actor_Query_Goal_Number(kActorHowieLee) < 100
50 		 && Global_Variable_Query(kVariableChapter) == 4
51 		) {
52 			Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToFreeSlotC);
53 		}
54 
55 		if (Global_Variable_Query(kVariableChapter) > 3) {
56 			return true;
57 		}
58 	} else {
59 		if (Actor_Query_Goal_Number(kActorHowieLee) < 100
60 		 && Global_Variable_Query(kVariableChapter) == 2
61 		) {
62 			Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToFreeSlotC);
63 		}
64 
65 		if (Global_Variable_Query(kVariableChapter) > 1) {
66 			return true;
67 		}
68 	}
69 
70 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeDefault) {
71 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeMovesInDiner01);
72 	}
73 
74 	// In the original code this is used (in Act 1) to get Howie back to the Diner
75 	// from goals kGoalHowieLeeGoesToCT04GarbageBin or kGoalHowieLeeGoesToFreeSlotH
76 	// It might cause a blink-in issue, depending when update() will be called for Howie
77 	// This is kept as a backup while similar code is placed in the CT01 and CT02 scenes InitializeScene()
78 	// that will handle Howie appearing there immediately (fix for blink in)
79 	if (Game_Flag_Query(kFlagMcCoyInChinaTown)
80 	    && !Actor_Query_In_Set(kActorHowieLee, kSetCT01_CT12)) {
81 		AI_Movement_Track_Flush(kActorHowieLee);
82 		AI_Movement_Track_Append(kActorHowieLee, 67, 0); // in kSetCT01_CT12
83 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
84 	}
85 
86 #if BLADERUNNER_ORIGINAL_BUGS
87 	if ( Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner01
88 	 &&  Game_Flag_Query(kFlagCT01BoughtHowieLeeFood)
89 	 && !Game_Flag_Query(kFlagMcCoyInChinaTown) ) {
90 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToCT04GarbageBin);
91 		return true;
92 	}
93 #else
94 	// Prevents possibility of Howie Lee from blinking in/out of existence
95 	// when the fly-out loop is playing and/or when McCoy enters and exits the Spinner with the spinner doors animation restored
96 	if ((Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner01
97 	     || Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner02
98 	     || Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner03
99 	     || Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner06
100 	     || Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeDefault)
101 	     &&  Game_Flag_Query(kFlagCT01BoughtHowieLeeFood)
102 	     && !Game_Flag_Query(kFlagMcCoyInChinaTown)
103 	     &&  Player_Query_Current_Scene() != kSceneCT01
104 	     &&  Player_Query_Current_Scene() != kSceneCT12
105 	) {
106 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToCT04GarbageBin);
107 		return true;
108 	}
109 #endif // BLADERUNNER_ORIGINAL_BUGS
110 
111 	return false;
112 }
113 
TimerExpired(int timer)114 void AIScriptHowieLee::TimerExpired(int timer) {
115 	//return false;
116 }
117 
CompletedMovementTrack()118 void AIScriptHowieLee::CompletedMovementTrack() {
119 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner01) {
120 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeMovesInDiner02);
121 		return; // true;
122 	}
123 
124 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner02) {
125 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeMovesInDiner03);
126 		return; // true;
127 	}
128 
129 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner03) {
130 		if (_vm->_cutContent) {
131 			//
132 			// *after Act 1* Howie will be going to the Garbage Bin "semi-regularly"
133 			// if McCoy is not in scenes CT01 and CT12 (where Howie is visible working at the diner)
134 			// otherwise he'll do the short cycle (goals 0, 1, 2, 3)
135 			if (Global_Variable_Query(kVariableChapter) > 1
136 			    && Player_Query_Current_Scene() != kSceneCT01
137 			    && Player_Query_Current_Scene() != kSceneCT12
138 			    && Player_Query_Current_Scene() != kSceneCT04
139 			    && Random_Query(1, 5) == 1
140 			) {
141 				Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToCT04GarbageBin);
142 				return; // true;
143 			} else {
144 				Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
145 				return; // true;
146 			}
147 		} else {
148 			Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
149 			return; // true;
150 		}
151 	}
152 
153 #if BLADERUNNER_ORIGINAL_BUGS
154 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeMovesInDiner03) {
155 			Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToCT04GarbageBin);
156 			return; // true;
157 	}
158 #endif // BLADERUNNER_ORIGINAL_BUGS
159 
160 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeGoesToCT04GarbageBin) {
161 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToFreeSlotH);
162 		return; // true;
163 	}
164 
165 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeGoesToFreeSlotH) {
166 #if BLADERUNNER_ORIGINAL_BUGS
167 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
168 		return; // true;
169 #else
170 		// don't blink-in and also only return to diner routine if McCoy is actually in Chinatown
171 		if (Game_Flag_Query(kFlagMcCoyInChinaTown)
172 		    && Player_Query_Current_Scene() != kSceneCT01
173 		    && Player_Query_Current_Scene() != kSceneCT12
174 		) {
175 			Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
176 			return; // true;
177 		} else {
178 			// return to "garbage bin" goal instead of blinking in
179 			Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeGoesToCT04GarbageBin);
180 			return; // true;
181 		}
182 #endif // BLADERUNNER_ORIGINAL_BUGS
183 	}
184 
185 	// return false;
186 }
187 
ReceivedClue(int clueId,int fromActorId)188 void AIScriptHowieLee::ReceivedClue(int clueId, int fromActorId) {
189 	//return false;
190 }
191 
ClickedByPlayer()192 void AIScriptHowieLee::ClickedByPlayer() {
193 	//return false;
194 }
195 
EnteredScene(int sceneId)196 void AIScriptHowieLee::EnteredScene(int sceneId) {
197 	if (Actor_Query_Goal_Number(kActorHowieLee) == kGoalHowieLeeGoesToCT04GarbageBin
198 	 && Actor_Query_In_Set(kActorHowieLee, kSetCT03_CT04)
199 	) {
200 		if ( Game_Flag_Query(kFlagCT04HomelessKilledByMcCoy)
201 		 && !Game_Flag_Query(kFlagCT04HomelessBodyInDumpster)
202 		 && !Game_Flag_Query(kFlagCT04HomelessBodyFound)
203 #if BLADERUNNER_ORIGINAL_BUGS
204 #else
205 		 && !Game_Flag_Query(kFlagCT04HomelessBodyThrownAway)
206 #endif // BLADERUNNER_ORIGINAL_BUGS
207 		) {
208 			Game_Flag_Set(kFlagCT04HomelessBodyFound);
209 			// return false;
210 		}
211 
212 		if (Game_Flag_Query(kFlagCT04HomelessKilledByMcCoy)
213 		 &&  Game_Flag_Query(kFlagCT04HomelessBodyInDumpster)
214 		 && !Game_Flag_Query(kFlagCT04HomelessBodyFound)
215 #if BLADERUNNER_ORIGINAL_BUGS
216 #else
217 		 && !Game_Flag_Query(kFlagCT04HomelessBodyThrownAway)
218 #endif // BLADERUNNER_ORIGINAL_BUGS
219 		 &&  Random_Query(1, 10) == 1
220 		) {
221 			Game_Flag_Set(kFlagCT04HomelessBodyFound);
222 			// return true;
223 		}
224 		// return false;
225 	}
226 }
227 
OtherAgentEnteredThisScene(int otherActorId)228 void AIScriptHowieLee::OtherAgentEnteredThisScene(int otherActorId) {
229 #if BLADERUNNER_ORIGINAL_BUGS
230 #else
231 	// prevent player from actually meeting hovering Howie half-body in kSetCT03_CT04
232 	if (otherActorId == kActorMcCoy
233 	    && Actor_Query_In_Set(kActorHowieLee, kSetCT03_CT04)
234 	) {
235 		AI_Movement_Track_Flush(kActorHowieLee);
236 		AI_Movement_Track_Append(kActorHowieLee, 67, 0); // in kSetCT01_CT12
237 		Actor_Set_Goal_Number(kActorHowieLee, kGoalHowieLeeDefault);
238 	}
239 #endif // BLADERUNNER_ORIGINAL_BUGS
240 	// return false;
241 }
242 
OtherAgentExitedThisScene(int otherActorId)243 void AIScriptHowieLee::OtherAgentExitedThisScene(int otherActorId) {
244 	// return false;
245 }
246 
OtherAgentEnteredCombatMode(int otherActorId,int combatMode)247 void AIScriptHowieLee::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
248 	// return false;
249 }
250 
ShotAtAndMissed()251 void AIScriptHowieLee::ShotAtAndMissed() {
252 	// return false;
253 }
254 
ShotAtAndHit()255 bool AIScriptHowieLee::ShotAtAndHit() {
256 	return false;
257 }
258 
Retired(int byActorId)259 void AIScriptHowieLee::Retired(int byActorId) {
260 	// return false;
261 }
262 
GetFriendlinessModifierIfGetsClue(int otherActorId,int clueId)263 int AIScriptHowieLee::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
264 	return 0;
265 }
266 
GoalChanged(int currentGoalNumber,int newGoalNumber)267 bool AIScriptHowieLee::GoalChanged(int currentGoalNumber, int newGoalNumber) {
268 	switch (newGoalNumber) {
269 	case kGoalHowieLeeMovesInDiner01:
270 		AI_Movement_Track_Flush(kActorHowieLee);
271 		if (Random_Query(1, 2) == 1) {
272 			AI_Movement_Track_Append_With_Facing(kActorHowieLee, 67, Random_Query(3, 10), 720); // in kSetCT01_CT12
273 		} else {
274 			AI_Movement_Track_Append_With_Facing(kActorHowieLee, 69, Random_Query(3, 10), 640); // in kSetCT01_CT12
275 		}
276 		AI_Movement_Track_Repeat(kActorHowieLee);
277 		return true;
278 	case kGoalHowieLeeMovesInDiner02:
279 		AI_Movement_Track_Flush(kActorHowieLee);
280 		if (Random_Query(1, 2) == 1) {
281 			AI_Movement_Track_Append_With_Facing(kActorHowieLee, 68, Random_Query(3, 10), 641); // in kSetCT01_CT12
282 		} else {
283 			AI_Movement_Track_Append_With_Facing(kActorHowieLee, 67, Random_Query(3, 10), 720); // in kSetCT01_CT12
284 		}
285 		AI_Movement_Track_Repeat(kActorHowieLee);
286 		return true;
287 	case kGoalHowieLeeMovesInDiner03:
288 		AI_Movement_Track_Flush(kActorHowieLee);
289 		if (Random_Query(1, 2) == 1) {
290 			AI_Movement_Track_Append_With_Facing(kActorHowieLee, 69, Random_Query(3, 10), 640); // in kSetCT01_CT12
291 		} else {
292 			AI_Movement_Track_Append_With_Facing(kActorHowieLee, 68, Random_Query(3, 10), 641); // in kSetCT01_CT12
293 		}
294 		AI_Movement_Track_Repeat(kActorHowieLee);
295 		return true;
296 	case kGoalHowieLeeGoesToCT04GarbageBin:
297 		AI_Movement_Track_Flush(kActorHowieLee);
298 		AI_Movement_Track_Append(kActorHowieLee, 66, 30);  // in kSetCT03_CT04
299 		AI_Movement_Track_Repeat(kActorHowieLee);
300 		return true;
301 	case kGoalHowieLeeGoesToFreeSlotH:
302 		AI_Movement_Track_Flush(kActorHowieLee);
303 		AI_Movement_Track_Append(kActorHowieLee, 40, 60);  // in kSetFreeSlotH
304 		AI_Movement_Track_Repeat(kActorHowieLee);
305 		return true;
306 	case kGoalHowieLeeMovesInDiner06: // Unused goal?
307 		AI_Movement_Track_Flush(kActorHowieLee);
308 		AI_Movement_Track_Append(kActorHowieLee, 67, 90); // in kSetCT01_CT12
309 		AI_Movement_Track_Repeat(kActorHowieLee);
310 		return true;
311 	case kGoalHowieLeeStopMoving:
312 		AI_Movement_Track_Flush(kActorHowieLee);
313 		return false;
314 	case kGoalHowieLeeGoesToFreeSlotC:
315 		AI_Movement_Track_Flush(kActorHowieLee);
316 		Actor_Put_In_Set(kActorHowieLee, kSetFreeSlotC);
317 		Actor_Set_At_Waypoint(kActorHowieLee, 35, 0); // in kSetFreeSlotC
318 		return false;
319 	}
320 	return false;
321 }
322 
UpdateAnimation(int * animation,int * frame)323 bool AIScriptHowieLee::UpdateAnimation(int *animation, int *frame) {
324 	switch (_animationState) {
325 	case 0:
326 		_animationFrame++;
327 		if (var_45DFB8) {
328 			*animation = 673;
329 			if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(673)) {
330 				_animationFrame = 0;
331 				if (Random_Query(0, 2) > 0) {
332 					var_45DFB8 ^= 1;
333 				}
334 			}
335 		} else {
336 			*animation = 671;
337 			if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(671)) {
338 				_animationFrame = 0;
339 				if (Random_Query(0, 1) > 0) {
340 					var_45DFB8 ^= 1;
341 				}
342 			}
343 		}
344 		break;
345 	case 1:
346 		*animation = 674;
347 		_animationFrame++;
348 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(674)) {
349 			_animationFrame = 0;
350 			if (_animationState < 3 || _animationState > 8) {
351 				_animationState = 0;
352 				_animationFrame = 0;
353 				var_45DFB8 = Random_Query(0, 1);
354 			} else {
355 				Game_Flag_Set(kFlagHowieLeeAnimation1);
356 			}
357 			*animation = 673;
358 		}
359 		break;
360 	case 2:
361 		*animation = 672;
362 		_animationFrame++;
363 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(672)) {
364 			_animationFrame = 0;
365 		}
366 		break;
367 	case 3:
368 		if (Game_Flag_Query(kFlagHowieLeeAnimation1)) {
369 			Game_Flag_Reset(kFlagHowieLeeAnimation1);
370 			_animationState = 0;
371 			_animationFrame = 0;
372 			var_45DFB8 = Random_Query(0, 1);
373 			*animation = 671;
374 		} else {
375 			_animationFrame++;
376 			if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(676)) {
377 				_animationFrame = 0;
378 			}
379 			*animation = 676;
380 		}
381 		break;
382 	case 4:
383 		*animation = 677;
384 		_animationFrame++;
385 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(677)) {
386 			_animationState = 3;
387 			_animationFrame = 0;
388 			*animation = 676;
389 		}
390 		break;
391 	case 5:
392 		*animation = 678;
393 		_animationFrame++;
394 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(678)) {
395 			_animationState = 3;
396 			_animationFrame = 0;
397 			*animation = 676;
398 		}
399 		break;
400 	case 6:
401 		*animation = 679;
402 		_animationFrame++;
403 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(679)) {
404 			_animationState = 3;
405 			_animationFrame = 0;
406 			*animation = 676;
407 		}
408 		break;
409 	case 7:
410 		*animation = 680;
411 		_animationFrame++;
412 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(680)) {
413 			_animationState = 3;
414 			_animationFrame = 0;
415 			*animation = 676;
416 		}
417 		break;
418 	case 8:
419 		*animation = 681;
420 		_animationFrame++;
421 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(681)) {
422 			_animationState = 3;
423 			_animationFrame = 0;
424 			*animation = 676;
425 		}
426 		break;
427 	default:
428 		*animation = 399;
429 		break;
430 	}
431 	*frame = _animationFrame;
432 	return true;
433 }
434 
ChangeAnimationMode(int mode)435 bool AIScriptHowieLee::ChangeAnimationMode(int mode) {
436 	switch (mode) {
437 	case kAnimationModeIdle:
438 		if (_animationState < 3 || _animationState > 8) {
439 			_animationState = 0;
440 			_animationFrame = 0;
441 			var_45DFB8 = Random_Query(0, 1);
442 		} else {
443 			Game_Flag_Set(kFlagHowieLeeAnimation1);
444 		}
445 		break;
446 	case kAnimationModeWalk:
447 		if (_animationState != 2) {
448 			_animationState = 2;
449 			_animationFrame = 0;
450 		}
451 		break;
452 	case kAnimationModeTalk:
453 		_animationState = 3;
454 		_animationFrame = 0;
455 		break;
456 	case 12:
457 		_animationState = 4;
458 		_animationFrame = 0;
459 		break;
460 	case 13:
461 		_animationState = 5;
462 		_animationFrame = 0;
463 		break;
464 	case 14:
465 		_animationState = 6;
466 		_animationFrame = 0;
467 		break;
468 	case 15:
469 		_animationState = 7;
470 		_animationFrame = 0;
471 		break;
472 	case 16:
473 		_animationState = 8;
474 		_animationFrame = 0;
475 		break;
476 	case 43:
477 		_animationState = 1;
478 		_animationFrame = 0;
479 		break;
480 	}
481 	return true;
482 }
483 
QueryAnimationState(int * animationState,int * animationFrame,int * animationStateNext,int * animationNext)484 void AIScriptHowieLee::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
485 	*animationState     = _animationState;
486 	*animationFrame     = _animationFrame;
487 	*animationStateNext = _animationStateNext;
488 	*animationNext      = _animationNext;
489 }
490 
SetAnimationState(int animationState,int animationFrame,int animationStateNext,int animationNext)491 void AIScriptHowieLee::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
492 	_animationState     = animationState;
493 	_animationFrame     = animationFrame;
494 	_animationStateNext = animationStateNext;
495 	_animationNext      = animationNext;
496 }
497 
ReachedMovementTrackWaypoint(int waypointId)498 bool AIScriptHowieLee::ReachedMovementTrackWaypoint(int waypointId) {
499 	if (waypointId == 67 && Random_Query(1, 2) == 2) {
500 		Actor_Face_Heading(kActorHowieLee, 850, 0);
501 		_animationFrame = 0;
502 		_animationState = 1;
503 	}
504 	return true;
505 }
506 
FledCombat()507 void AIScriptHowieLee::FledCombat() {
508 	// return false;
509 }
510 
511 } // End of namespace BladeRunner
512