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