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