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 "common/config-manager.h"
24 
25 #include "ultima/ultima8/world/actors/actor_anim_process.h"
26 #include "ultima/ultima8/world/actors/anim_action.h"
27 #include "ultima/ultima8/world/actors/main_actor.h"
28 #include "ultima/ultima8/misc/direction_util.h"
29 #include "ultima/ultima8/world/world.h"
30 #include "ultima/ultima8/kernel/kernel.h"
31 #include "ultima/ultima8/usecode/uc_list.h"
32 #include "ultima/ultima8/world/loop_script.h"
33 #include "ultima/ultima8/world/current_map.h"
34 #include "ultima/ultima8/world/actors/animation_tracker.h"
35 #include "ultima/ultima8/audio/audio_process.h"
36 #include "ultima/ultima8/world/actors/combat_process.h"
37 #include "ultima/ultima8/world/actors/auto_firer_process.h"
38 #include "ultima/ultima8/world/sprite_process.h"
39 #include "ultima/ultima8/graphics/palette_fader_process.h"
40 #include "ultima/ultima8/world/create_item_process.h"
41 #include "ultima/ultima8/world/destroy_item_process.h"
42 #include "ultima/ultima8/kernel/delay_process.h"
43 #include "ultima/ultima8/world/get_object.h"
44 
45 namespace Ultima {
46 namespace Ultima8 {
47 
48 //#define WATCHACTOR 1
49 
50 #ifdef WATCHACTOR
51 static const int watchactor = WATCHACTOR;
52 #endif
53 
DEFINE_RUNTIME_CLASSTYPE_CODE(ActorAnimProcess)54 DEFINE_RUNTIME_CLASSTYPE_CODE(ActorAnimProcess)
55 
56 ActorAnimProcess::ActorAnimProcess() : Process(), _tracker(nullptr),
57 	_dir(dir_north), _action(Animation::walk), _steps(0), _firstFrame(true),
58 	_currentStep(0), _repeatCounter(0), _animAborted(false),
59 	_attackedSomething(false), _interpolate(false) {
60 }
61 
ActorAnimProcess(Actor * actor,Animation::Sequence action,Direction dir,uint32 steps)62 ActorAnimProcess::ActorAnimProcess(Actor *actor, Animation::Sequence action,
63 								   Direction dir, uint32 steps) :
64 		_dir(dir), _action(action), _steps(steps), _tracker(nullptr),
65 		_firstFrame(true), _currentStep(0), _repeatCounter(0),
66 		_animAborted(false), _attackedSomething(false), _interpolate(false)  {
67 	assert(actor);
68 	_itemNum = actor->getObjId();
69 
70 	_type = ACTOR_ANIM_PROC_TYPE;
71 #ifdef WATCHACTOR
72 	if (_itemNum == watchactor)
73 		pout << "Animation [" << Kernel::get_instance()->getFrameNum()
74 			 << "] ActorAnimProcess created (" << _itemNum << ","
75 			 << _action << "," << _dir << ") steps " << _steps
76 			 << Std::endl;
77 #endif
78 }
79 
init()80 bool ActorAnimProcess::init() {
81 	_repeatCounter = 0;
82 	_animAborted = false;
83 	_attackedSomething = false;
84 
85 	_interpolate = Ultima8Engine::get_instance()->isInterpolationEnabled();
86 
87 	Actor *actor = getActor(_itemNum);
88 	assert(actor);
89 
90 	if (_dir == dir_current)
91 		_dir = actor->getDir();
92 
93 	if (!actor->hasFlags(Item::FLG_FASTAREA)) {
94 		// not in the fast area? Can't play an animation then.
95 		// (If we do, the actor will likely fall because the floor is gone.)
96 
97 #ifdef WATCHACTOR
98 	if (_itemNum == watchactor)
99 		pout << "Animation [" << Kernel::get_instance()->getFrameNum()
100 			 << "] ActorAnimProcess " << getPid() << " init failed "
101 			 << "(actor " << _itemNum << "not fast)" << Std::endl;
102 #endif
103 
104 		return false;
105 	}
106 
107 	if (actor->hasActorFlags(Actor::ACT_ANIMLOCK)) {
108 		//! What do we do if actor was already animating?
109 		//! don't do this animation or kill the previous one?
110 		//! Or maybe wait until the previous one finishes?
111 
112 		perr << "ActorAnimProcess [" << getPid() << "]: ANIMLOCK set on actor "
113 		     << _itemNum << ", skipping anim (" << _action << "," << _dir << ")"
114 			 << Std::endl;
115 
116 		// for now, just don't play this one.
117 		return false;
118 	}
119 
120 	_tracker = new AnimationTracker();
121 	if (!_tracker->init(actor, _action, _dir)) {
122 		delete _tracker;
123 		_tracker = nullptr;
124 
125 #ifdef WATCHACTOR
126 	if (_itemNum == watchactor)
127 		pout << "Animation [" << Kernel::get_instance()->getFrameNum()
128 			 << "] ActorAnimProcess " << getPid() << " init failed "
129 			 << "(tracker init failed)" << Std::endl;
130 #endif
131 
132 		return false;
133 	}
134 
135 	actor->setActorFlag(Actor::ACT_ANIMLOCK);
136 
137 	actor->_lastAnim = _action;
138 	actor->_direction = _dir;
139 
140 
141 #ifdef WATCHACTOR
142 	if (_itemNum == watchactor)
143 		pout << "Animation [" << Kernel::get_instance()->getFrameNum()
144 		     << "] ActorAnimProcess " << getPid() << " initalized ("
145 			 << _itemNum << "," << _action << "," << _dir << ") steps "
146 			 << _steps << Std::endl;
147 #endif
148 
149 	return true;
150 }
151 
152 
run()153 void ActorAnimProcess::run() {
154 	if (_firstFrame) {
155 		bool ret = init();
156 		if (!ret) {
157 			// initialization failed
158 			terminateDeferred();
159 			return;
160 		}
161 	}
162 
163 	if (_animAborted) {
164 		terminate();
165 		return;
166 	}
167 
168 	assert(_tracker);
169 
170 	if (!_firstFrame)
171 		_repeatCounter++;
172 	if (_repeatCounter > _tracker->getAnimAction()->getFrameRepeat())
173 		_repeatCounter = 0;
174 
175 	Actor *a = getActor(_itemNum);
176 	if (!a) {
177 		// actor gone
178 		terminate();
179 		return;
180 	}
181 
182 	_firstFrame = false;
183 
184 	if (!a->hasFlags(Item::FLG_FASTAREA)) {
185 		// not in the fast area? Kill the animation then.
186 		//! TODO: Decide if this is the right move.
187 		//  Animation could do one of three things: pause, move
188 		//  without allowing actor to fall, or pretend to move and
189 		//  complete the entire movement as the actor reappears
190 		//  in fast area (still may need to pause when
191 		//  AnimationTracker is done.)
192 #ifdef WATCHACTOR
193 		if (_itemNum == watchactor)
194 			pout << "Animation ["
195 			     << Kernel::get_instance()->getFrameNum()
196 			     << "] ActorAnimProcess left fastarea; terminating"
197 			     << Std::endl;
198 #endif
199 		terminate();
200 		return;
201 	}
202 
203 	bool resultVal = true;
204 	if (_repeatCounter == 0) {
205 		// next step:
206 		int32 x, y, z;
207 		a->getLocation(x, y, z);
208 		resultVal = _tracker->stepFrom(x, y, z);
209 		_tracker->updateActorFlags();
210 		_currentStep++;
211 
212 		if (!resultVal) {
213 			// check possible error conditions
214 
215 			if (_tracker->isDone() || (_steps && _currentStep >= _steps)) {
216 				// all done
217 #ifdef WATCHACTOR
218 				if (_itemNum == watchactor)
219 					pout << "Animation ["
220 					     << Kernel::get_instance()->getFrameNum()
221 					     << "] ActorAnimProcess done; terminating"
222 					     << Std::endl;
223 #endif
224 
225 				// TODO: there are _three_ places where we can fall; clean up
226 				if (_tracker->isUnsupported()) {
227 #ifdef WATCHACTOR
228 					if (_itemNum == watchactor) {
229 						pout << "Animation ["
230 						     << Kernel::get_instance()->getFrameNum()
231 						     << "] falling at end" << Std::endl;
232 					}
233 #endif
234 					int32 dx, dy, dz;
235 					_tracker->getSpeed(dx, dy, dz);
236 					a->hurl(dx, dy, dz, 2);
237 				}
238 
239 				terminate();
240 				return;
241 			}
242 
243 			if (_tracker->isBlocked() &&
244 				!_tracker->getAnimAction()->hasFlags(AnimAction::AAF_UNSTOPPABLE)) {
245 				// FIXME: For blocked large steps we may still want to do
246 				//        a partial move. (But how would that work with
247 				//        repeated frames?)
248 
249 #ifdef WATCHACTOR
250 				if (_itemNum == watchactor)
251 					pout << "Animation ["
252 					     << Kernel::get_instance()->getFrameNum()
253 					     << "] ActorAnimProcess blocked; terminating"
254 					     << Std::endl;
255 #endif
256 
257 				if (_tracker->isUnsupported()) {
258 #ifdef WATCHACTOR
259 					if (_itemNum == watchactor) {
260 						pout << "Animation ["
261 						     << Kernel::get_instance()->getFrameNum()
262 						     << "] falling from blocked" << Std::endl;
263 					}
264 #endif
265 					// no inertia here because we just crashed into something
266 					a->fall();
267 				}
268 
269 
270 				terminate();
271 				return;
272 			}
273 		}
274 
275 		const AnimFrame *curframe = _tracker->getAnimFrame();
276 		if (curframe) {
277 			if (curframe->_sfx) {
278 				AudioProcess *audioproc = AudioProcess::get_instance();
279 				if (audioproc) audioproc->playSFX(curframe->_sfx, 0x60, _itemNum, 0);
280 			}
281 
282 			if (curframe->_flags & AnimFrame::AFF_SPECIAL) {
283 				// Flag to trigger a special action
284 				// E.g.: play draw/sheathe SFX for avatar when weapon equipped,
285 				// throw skull-fireball when ghost attacks, ...
286 				doSpecial();
287 			} else if (curframe->_flags & AnimFrame::AFF_HURTY && GAME_IS_CRUSADER) {
288 				a->tookHitCru();
289 			} else if (curframe->is_cruattack() && GAME_IS_CRUSADER) {
290 				doFireWeaponCru(a, curframe);
291 			}
292 		}
293 
294 
295 		// attacking?
296 		if (!_attackedSomething) {
297 			ObjId hit = _tracker->hitSomething();
298 			if (hit) {
299 				_attackedSomething = true;
300 				Item *hit_item = getItem(hit);
301 				assert(hit_item);
302 				hit_item->receiveHit(_itemNum, Direction_Invert(_dir), 0, 0);
303 				doHitSpecial(hit_item);
304 			}
305 		}
306 	}
307 
308 	int32 x, y, z, x2, y2, z2;
309 	a->getLocation(x, y, z);
310 
311 	if (_interpolate) {
312 		// Apply interpolated position on repeated frames
313 		_tracker->getInterpolatedPosition(x2, y2, z2, _repeatCounter);
314 		if (x == x2 && y == y2 && z == z2) {
315 			_tracker->getInterpolatedPosition(x, y, z, _repeatCounter + 1);
316 			a->collideMove(x, y, z, false, true); // forced move
317 			a->setFrame(_tracker->getFrame());
318 #ifdef WATCHACTOR
319 		} else {
320 			if (_itemNum == watchactor) {
321 				pout << "Animation [" << Kernel::get_instance()->getFrameNum()
322 					 << "] moved, so aborting this frame." << Std::endl;
323 			}
324 #endif // WATCHACTOR
325 		}
326 	} else {
327 		// Just move the whole distance on frame 0 of the repeat.
328 		if (_repeatCounter == 0) {
329 			_tracker->getPosition(x2, y2, z2);
330 			a->collideMove(x2, y2, z2, false, true); // forced move
331 			a->setFrame(_tracker->getFrame());
332 		} else {
333 			x2 = x;
334 			y2 = y;
335 			z2 = z;
336 		}
337 	}
338 
339 	// Did we just leave the fast area?
340 	if (!a->hasFlags(Item::FLG_FASTAREA)) {
341 #ifdef WATCHACTOR
342 		if (_itemNum == watchactor)
343 			pout << "Animation ["
344 			     << Kernel::get_instance()->getFrameNum()
345 			     << "] ActorAnimProcess left fastarea; terminating"
346 			     << Std::endl;
347 #endif
348 		terminate();
349 		return;
350 	}
351 
352 #ifdef WATCHACTOR
353 	if (_itemNum == watchactor) {
354 		pout << "Animation [" << Kernel::get_instance()->getFrameNum()
355 		     << "] showing frame (" << x << "," << y << "," << z << ")-("
356 			 << x2 << "," << y2 << "," << z2 << ")"
357 		     << " shp (" << a->getShape() << "," << _tracker->getFrame()
358 		     << ") sfx " << _tracker->getAnimFrame()->_sfx
359 		     << " rep " << _repeatCounter << ConsoleStream::hex
360 			 << " flg " << _tracker->getAnimFrame()->_flags << " "
361 			 << ConsoleStream::dec;
362 
363 		if (_tracker->isDone()) pout << "D";
364 		if (_tracker->isBlocked()) pout << "B";
365 		if (_tracker->isUnsupported()) pout << "U";
366 		if (_tracker->hitSomething()) pout << "H";
367 		pout << Std::endl;
368 	}
369 #endif
370 
371 
372 	if (_repeatCounter == _tracker->getAnimAction()->getFrameRepeat()) {
373 		if (_tracker->isUnsupported()) {
374 			_animAborted = !_tracker->getAnimAction()->hasFlags(AnimAction::AAF_UNSTOPPABLE);
375 
376 #ifdef WATCHACTOR
377 			if (_itemNum == watchactor) {
378 				pout << "Animation [" << Kernel::get_instance()->getFrameNum()
379 				     << "] falling from repeat" << Std::endl;
380 			}
381 #endif
382 
383 			int32 dx, dy, dz;
384 			_tracker->getSpeed(dx, dy, dz);
385 			if (GAME_IS_CRUSADER) {
386 				// HACK: Hurl people a bit less hard in crusader until
387 				// the movement bugs are fixed to make them fall less..
388 				dx /= 4;
389 				dy /= 4;
390 				dz /= 4;
391 			}
392 			a->hurl(dx, dy, dz, 2);
393 
394 			// Note: do not wait for the fall to finish: this breaks
395 			// the scene where Devon kills Mordea
396 			return;
397 		}
398 	}
399 }
400 
doSpecial()401 void ActorAnimProcess::doSpecial() {
402 	Actor *a = getActor(_itemNum);
403 	assert(a);
404 
405 	// All this stuff is U8 specific.
406 	if (!GAME_IS_U8)
407 		return;
408 
409 	// play SFX when Avatar draws/sheathes weapon
410 	if (_itemNum == 1 && (_action == Animation::readyWeapon ||
411 	                      _action == Animation::unreadyWeapon) &&
412 	        a->getEquip(ShapeInfo::SE_WEAPON) != 0) {
413 		int sfx = (getRandom() % 2) ? 0x51 : 0x52; // constants!
414 		AudioProcess *audioproc = AudioProcess::get_instance();
415 		if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0);
416 		return;
417 	}
418 
419 	// ghosts
420 	if (a->getShape() == 0x19b) {
421 		Actor *hostile = nullptr;
422 		if (_action == Animation::attack) {
423 			// fireball on attack
424 			unsigned int skullcount = a->countNearby(0x19d, 6 * 256);
425 			if (skullcount > 5) return;
426 
427 			Actor *skull = Actor::createActor(0x19d, 0);
428 			if (!skull) return;
429 			skull->setFlag(Item::FLG_FAST_ONLY);
430 			int32 x, y, z;
431 			a->getLocation(x, y, z);
432 			Direction dirNum = a->getDir();
433 			skull->move(x + 32 * Direction_XFactor(dirNum), y + 32 * Direction_XFactor(dirNum), z);
434 			hostile = skull;
435 		} else if (a->getMapNum() != 54) { // Khumash-Gor doesn't summon ghouls
436 			// otherwise, summon ghoul
437 			unsigned int ghoulcount = a->countNearby(0x8e, 8 * 256);
438 			if (ghoulcount > 2) return;
439 
440 			int32 x, y, z;
441 			a->getLocation(x, y, z);
442 			x += (getRandom() % (6 * 256)) - 3 * 256;
443 			y += (getRandom() % (6 * 256)) - 3 * 256;
444 
445 			Actor *ghoul = Actor::createActor(0x8e, 0);
446 			if (!ghoul) return;
447 			ghoul->setFlag(Item::FLG_FAST_ONLY);
448 			if (!ghoul->canExistAt(x, y, z, true)) {
449 				ghoul->destroy();
450 				return;
451 			}
452 			ghoul->move(x, y, z);
453 			ghoul->doAnim(Animation::standUp, dir_north);
454 			hostile = ghoul;
455 		}
456 
457 		if (hostile) {
458 			// Note: only happens in U8, so activity num is not important.
459 			hostile->setInCombat(0);
460 			CombatProcess *hostilecp = hostile->getCombatProcess();
461 			CombatProcess *cp = a->getCombatProcess();
462 			if (hostilecp && cp)
463 				hostilecp->setTarget(cp->getTarget());
464 		}
465 
466 		return;
467 	}
468 
469 	// ghost's fireball
470 	if (a->getShape() == 0x19d) {
471 		Actor *av = getMainActor();
472 		if (a->getRange(*av) < 96) {
473 			a->setActorFlag(Actor::ACT_DEAD);
474 			a->explode(0, true); // explode if close to the avatar
475 		}
476 		return;
477 	}
478 
479 	// play PC/NPC footsteps
480 	bool playavfootsteps = ConfMan.getBool("footsteps");
481 	if (_itemNum != 1 || playavfootsteps) {
482 		UCList itemlist(2);
483 		LOOPSCRIPT(script, LS_TOKEN_TRUE);
484 		CurrentMap *cm = World::get_instance()->getCurrentMap();
485 
486 		// find items directly below
487 		cm->surfaceSearch(&itemlist, script, sizeof(script), a, false, true);
488 		if (itemlist.getSize() == 0) return;
489 
490 		Item *f = getItem(itemlist.getuint16(0));
491 		assert(f);
492 
493 		uint32 floor = f->getShape();
494 		bool running = (_action == Animation::run);
495 		bool splash = false;
496 		int sfx = 0;
497 		switch (floor) { // lots of constants!!
498 		case 0x03:
499 		case 0x04:
500 		case 0x09:
501 		case 0x0B:
502 		case 0x5C:
503 		case 0x5E:
504 			sfx = 0x2B;
505 			break;
506 		case 0x7E:
507 		case 0x80:
508 			sfx = 0xCD;
509 			splash = true;
510 			break;
511 		case 0xA1:
512 		case 0xA2:
513 		case 0xA3:
514 		case 0xA4:
515 			sfx = (running ? 0x99 : 0x91);
516 			break;
517 		default:
518 			sfx = (running ? 0x97 : 0x90);
519 			break;
520 		}
521 
522 		if (sfx) {
523 			AudioProcess *audioproc = AudioProcess::get_instance();
524 			if (audioproc) audioproc->playSFX(sfx, 0x60, _itemNum, 0, false, 0x10000 + (getRandom() & 0x1FFF) - 0x1000);
525 		}
526 
527 		if (splash) {
528 			int32 x, y, z;
529 			a->getLocation(x, y, z);
530 			Process *sp = new SpriteProcess(475, 0, 7, 1, 1, x, y, z);
531 			Kernel::get_instance()->addProcess(sp);
532 		}
533 	}
534 
535 }
536 
doFireWeaponCru(Actor * a,const AnimFrame * f)537 void ActorAnimProcess::doFireWeaponCru(Actor *a, const AnimFrame *f) {
538 	assert(a);
539 	assert(f);
540 	if (!f->is_cruattack())
541 		return;
542 
543 	const Item *wpn = getItem(a->getActiveWeapon());
544 	if (!wpn)
545 		return;
546 	const ShapeInfo *wpninfo = wpn->getShapeInfo();
547 	if (!wpninfo || !wpninfo->_weaponInfo)
548 		return;
549 
550 	if (a->getObjId() == 1 && wpninfo->_weaponInfo->_damageType == 6) {
551 		Process *auto_firer = new AutoFirerProcess();
552 		Kernel::get_instance()->addProcess(auto_firer);
553 	}
554 
555 	a->fireWeapon(f->cru_attackx(), f->cru_attacky(), f->cru_attackz(),
556 				  a->getDir(), wpninfo->_weaponInfo->_damageType, true);
557 
558 	AudioProcess *audioproc = AudioProcess::get_instance();
559 	if (audioproc)
560 		audioproc->playSFX(wpninfo->_weaponInfo->_sound, 0x80, a->getObjId(), 0, false);
561 }
562 
563 
564 
doHitSpecial(Item * hit)565 void ActorAnimProcess::doHitSpecial(Item *hit) {
566 	Actor *a = getActor(_itemNum);
567 	assert(a);
568 
569 	Actor *attacked = dynamic_cast<Actor *>(hit);
570 
571 	if (_itemNum == 1 && _action == Animation::attack) {
572 		// some magic weapons have some special effects
573 
574 		AudioProcess *audioproc = AudioProcess::get_instance();
575 
576 		MainActor *av = getMainActor();
577 		ObjId weaponid = av->getEquip(ShapeInfo::SE_WEAPON);
578 		Item *weapon = getItem(weaponid);
579 
580 		if (!weapon) return;
581 
582 		uint32 weaponshape = weapon->getShape();
583 
584 		switch (weaponshape) {
585 		case 0x32F: // magic hammer
586 			if (audioproc) audioproc->playSFX(23, 0x60, 1, 0, false,
587 				                                  0x10000 + (getRandom() & 0x1FFF) - 0x1000);
588 			break;
589 		case 0x330: { // Slayer
590 			// if we killed somebody, thunder&lightning
591 			if (attacked && attacked->hasActorFlags(Actor::ACT_DEAD)) {
592 				// calling intrinsic...
593 				PaletteFaderProcess::I_lightningBolt(0, 0);
594 				int sfx;
595 				switch (getRandom() % 3) {
596 				case 0:
597 					sfx = 91;
598 					break;
599 				case 1:
600 					sfx = 94;
601 					break;
602 				default:
603 					sfx = 96;
604 					break;
605 				}
606 				if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0);
607 			}
608 			break;
609 		}
610 		case 0x331: { // Flame Sting
611 			int sfx = 33;
612 			if (getRandom() % 2 == 0) sfx = 101;
613 			if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0, false,
614 				                                  0x10000 + (getRandom() & 0x1FFF) - 0x1000);
615 
616 			int32 x, y, z;
617 			a->getLocation(x, y, z);
618 			// 1: create flame sprite
619 			// 2: create flame object
620 			// 3: wait
621 			// 4a: destroy flame object
622 			// 4b: create douse-flame sprite
623 			Kernel *kernel = Kernel::get_instance();
624 
625 			int32 fx, fy, fz;
626 			fx = x + 96 * Direction_XFactor(_dir);
627 			fy = y + 96 * Direction_YFactor(_dir);
628 			fz = z;
629 
630 			// CONSTANTS!! (lots of them)
631 
632 			SpriteProcess *sp1 = new SpriteProcess(480, 0, 9, 1, 2, fx, fy, fz);
633 			kernel->addProcess(sp1);
634 
635 			DelayProcess *dp1 = new DelayProcess(3);
636 			ProcId dp1id = kernel->addProcess(dp1);
637 
638 			CreateItemProcess *cip = new CreateItemProcess(400, 0, 0,
639 			        Item::FLG_FAST_ONLY,
640 			        0, 0, 0, fx, fy, fz);
641 			ProcId cipid = kernel->addProcess(cip);
642 
643 			DelayProcess *dp2 = new DelayProcess(60 + (getRandom() % 60)); //2-4s
644 			ProcId dp2id = kernel->addProcess(dp2);
645 
646 			DestroyItemProcess *dip = new DestroyItemProcess(0);
647 			kernel->addProcess(dip);
648 
649 			SpriteProcess *sp2 = new SpriteProcess(381, 0, 9, 1, 1,
650 			                                       fx, fy, fz, true);
651 			kernel->addProcess(sp2);
652 
653 			cip->waitFor(dp1id);
654 			dp2->waitFor(cipid);
655 			dip->waitFor(dp2id);
656 			sp2->waitFor(dp2id);
657 
658 			break;
659 		}
660 		default:
661 			break;
662 		}
663 
664 		return ;
665 	}
666 
667 }
668 
terminate()669 void ActorAnimProcess::terminate() {
670 #ifdef WATCHACTOR
671 	if (_itemNum == watchactor)
672 		pout << "Animation ["
673 		     << Kernel::get_instance()->getFrameNum()
674 		     << "] ActorAnimProcess " << getPid() << " terminating"
675 		     << Std::endl;
676 #endif
677 
678 	Actor *a = getActor(_itemNum);
679 	if (a) {
680 		if (_tracker) { // if we were really animating...
681 			a->clearActorFlag(Actor::ACT_ANIMLOCK);
682 			if (_tracker->getAnimAction()->hasFlags(AnimAction::AAF_DESTROYACTOR)) {
683 				// destroy the actor
684 #ifdef WATCHACTOR
685 				if (_itemNum == watchactor)
686 					pout << "Animation ["
687 					     << Kernel::get_instance()->getFrameNum()
688 					     << "] ActorAnimProcess destroying actor " << _itemNum
689 					     << Std::endl;
690 #endif
691 				Process *vanishproc = new DestroyItemProcess(a);
692 				Kernel::get_instance()->addProcess(vanishproc);
693 
694 				return;
695 			}
696 		}
697 	}
698 
699 	delete _tracker;
700 
701 	Process::terminate();
702 }
703 
dumpInfo() const704 void ActorAnimProcess::dumpInfo() const {
705 	Process::dumpInfo();
706 	pout << "_action: " << _action << ", _dir: " << _dir << Std::endl;
707 }
708 
saveData(Common::WriteStream * ws)709 void ActorAnimProcess::saveData(Common::WriteStream *ws) {
710 	Process::saveData(ws);
711 
712 	uint8 ff = _firstFrame ? 1 : 0;
713 	ws->writeByte(ff);
714 	uint8 ab = _animAborted ? 1 : 0;
715 	ws->writeByte(ab);
716 	uint8 attacked = _attackedSomething ? 1 : 0;
717 	ws->writeByte(attacked);
718 	ws->writeByte(static_cast<uint8>(Direction_ToUsecodeDir(_dir)));
719 	ws->writeUint16LE(static_cast<uint16>(_action));
720 	ws->writeUint16LE(static_cast<uint16>(_steps));
721 	ws->writeUint16LE(static_cast<uint16>(_repeatCounter));
722 	ws->writeUint16LE(static_cast<uint16>(_currentStep));
723 
724 	if (_tracker) {
725 		ws->writeByte(1);
726 		_tracker->save(ws);
727 	} else
728 		ws->writeByte(0);
729 }
730 
loadData(Common::ReadStream * rs,uint32 version)731 bool ActorAnimProcess::loadData(Common::ReadStream *rs, uint32 version) {
732 	if (!Process::loadData(rs, version)) return false;
733 
734 	_firstFrame = (rs->readByte() != 0);
735 	_animAborted = (rs->readByte() != 0);
736 	_attackedSomething = (rs->readByte() != 0);
737 	_dir = Direction_FromUsecodeDir(rs->readByte());
738 	_action = static_cast<Animation::Sequence>(rs->readUint16LE());
739 	_steps = rs->readUint16LE();
740 	_repeatCounter = rs->readUint16LE();
741 	_currentStep = rs->readUint16LE();
742 
743 	assert(_tracker == nullptr);
744 	if (rs->readByte() != 0) {
745 		_tracker = new AnimationTracker();
746 		if (!_tracker->load(rs, version))
747 			return false;
748 	}
749 
750 	return true;
751 }
752 
753 } // End of namespace Ultima8
754 } // End of namespace Ultima
755