00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "ActorAnimProcess.h"
00022 #include "GameData.h"
00023 #include "Animation.h"
00024 #include "AnimDat.h"
00025 #include "AnimAction.h"
00026 #include "MainActor.h"
00027 #include "Direction.h"
00028 #include "World.h"
00029 #include "GravityProcess.h"
00030 #include "Kernel.h"
00031 #include "UCList.h"
00032 #include "LoopScript.h"
00033 #include "CurrentMap.h"
00034 #include "ShapeInfo.h"
00035 #include "AnimationTracker.h"
00036 #include "AudioProcess.h"
00037 #include "SettingManager.h"
00038 #include "CombatProcess.h"
00039 #include "SpriteProcess.h"
00040 #include "PaletteFaderProcess.h"
00041 #include "CreateItemProcess.h"
00042 #include "DestroyItemProcess.h"
00043 #include "DelayProcess.h"
00044 #include "getObject.h"
00045
00046 #include "IDataSource.h"
00047 #include "ODataSource.h"
00048
00049 #include <cstdlib>
00050
00051
00052
00053 #ifdef WATCHACTOR
00054 static const int watchactor = WATCHACTOR;
00055 #endif
00056
00057
00058 DEFINE_RUNTIME_CLASSTYPE_CODE(ActorAnimProcess,Process);
00059
00060 ActorAnimProcess::ActorAnimProcess() : Process(), tracker(0)
00061 {
00062
00063 }
00064
00065 ActorAnimProcess::ActorAnimProcess(Actor* actor_, Animation::Sequence action_,
00066 uint32 dir_, uint32 steps_)
00067 {
00068 assert(actor_);
00069 item_num = actor_->getObjId();
00070 dir = dir_;
00071 action = action_;
00072 steps = steps_;
00073
00074 type = 0x00F0;
00075 firstframe = true;
00076 tracker = 0;
00077 currentstep = 0;
00078 }
00079
00080 bool ActorAnimProcess::init()
00081 {
00082 repeatcounter = 0;
00083 animAborted = false;
00084 attackedSomething = false;
00085
00086 Actor* actor = getActor(item_num);
00087 assert(actor);
00088
00089 if (dir == 8)
00090 dir = actor->getDir();
00091
00092 if (dir > 7) {
00093
00094 return false;
00095 }
00096
00097 if (!(actor->getFlags() & Item::FLG_FASTAREA)) {
00098
00099
00100 return false;
00101 }
00102
00103 if (actor->getActorFlags() & Actor::ACT_ANIMLOCK) {
00107
00108 perr << "ActorAnimProcess [" << getPid() << "]: ANIMLOCK set on actor "
00109 << item_num << std::endl;
00110
00111
00112 return false;
00113 }
00114
00115 tracker = new AnimationTracker();
00116 if (!tracker->init(actor, action, dir)) {
00117 delete tracker;
00118 tracker = 0;
00119 return false;
00120 }
00121
00122 actor->setActorFlag(Actor::ACT_ANIMLOCK);
00123
00124 actor->lastanim = action;
00125 actor->direction = dir;
00126
00127
00128 #ifdef WATCHACTOR
00129 if (item_num == watchactor)
00130 pout << "Animation [" << Kernel::get_instance()->getFrameNum()
00131 << "] ActorAnimProcess " << getPid() << " created ("
00132 << action << "," << dir << ") steps " << steps << std::endl;
00133 #endif
00134
00135 return true;
00136 }
00137
00138
00139 bool ActorAnimProcess::run(const uint32 )
00140 {
00141 if (firstframe) {
00142 bool ret = init();
00143 if (!ret) {
00144
00145 terminateDeferred();
00146 return false;
00147 }
00148 }
00149
00150 if (animAborted) {
00151 terminate();
00152 return false;
00153 }
00154
00155 assert(tracker);
00156
00157 if (!firstframe)
00158 repeatcounter++;
00159 if (repeatcounter > tracker->getAnimAction()->framerepeat)
00160 repeatcounter = 0;
00161
00162 Actor *a = getActor(item_num);
00163 if (!a) {
00164
00165 terminate();
00166 return false;
00167 }
00168
00169 firstframe = false;
00170
00171 if (!(a->getFlags() & Item::FLG_FASTAREA)) {
00172
00174
00175
00176
00177
00178
00179 #ifdef WATCHACTOR
00180 if (item_num == watchactor)
00181 pout << "Animation ["
00182 << Kernel::get_instance()->getFrameNum()
00183 << "] ActorAnimProcess left fastarea; terminating"
00184 << std::endl;
00185 #endif
00186 terminate();
00187 return true;
00188 }
00189
00190 bool result = true;
00191 if (repeatcounter == 0) {
00192
00193 sint32 x,y,z;
00194 a->getLocation(x,y,z);
00195 result = tracker->stepFrom(x,y,z);
00196 tracker->updateActorFlags();
00197 currentstep++;
00198
00199 if (!result) {
00200
00201
00202 if (tracker->isDone() || (steps && currentstep >= steps) ) {
00203
00204 #ifdef WATCHACTOR
00205 if (item_num == watchactor)
00206 pout << "Animation ["
00207 << Kernel::get_instance()->getFrameNum()
00208 << "] ActorAnimProcess done; terminating"
00209 << std::endl;
00210 #endif
00211
00212
00213 if (tracker->isUnsupported()) {
00214 #ifdef WATCHACTOR
00215 if (item_num == watchactor) {
00216 pout << "Animation ["
00217 << Kernel::get_instance()->getFrameNum()
00218 << "] falling" << std::endl;
00219 }
00220 #endif
00221 sint32 dx,dy,dz;
00222 tracker->getSpeed(dx,dy,dz);
00223 a->hurl(dx,dy,dz,2);
00224 }
00225
00226 terminate();
00227 return true;
00228 }
00229
00230
00231 if (tracker->isBlocked() &&
00232 !(tracker->getAnimAction()->flags&AnimAction::AAF_UNSTOPPABLE))
00233 {
00234 #ifdef WATCHACTOR
00235 if (item_num == watchactor)
00236 pout << "Animation ["
00237 << Kernel::get_instance()->getFrameNum()
00238 << "] ActorAnimProcess blocked; terminating"
00239 << std::endl;
00240 #endif
00241
00242 if (tracker->isUnsupported()) {
00243 #ifdef WATCHACTOR
00244 if (item_num == watchactor) {
00245 pout << "Animation ["
00246 << Kernel::get_instance()->getFrameNum()
00247 << "] falling" << std::endl;
00248 }
00249 #endif
00250
00251 a->fall();
00252 }
00253
00254
00255 terminate();
00256 return true;
00257 }
00258 }
00259
00260 AnimFrame* curframe = tracker->getAnimFrame();
00261 if (curframe && curframe->sfx) {
00262 AudioProcess* audioproc = AudioProcess::get_instance();
00263 if (audioproc) audioproc->playSFX(curframe->sfx,0x60,item_num,0);
00264 }
00265
00266 if (curframe && (curframe->flags & AnimFrame::AFF_SPECIAL)) {
00267
00268
00269
00270 doSpecial();
00271 }
00272
00273
00274
00275 if (!attackedSomething) {
00276 ObjId hit = tracker->hitSomething();
00277 if (hit) {
00278 attackedSomething = true;
00279 Item* hit_item = getItem(hit);
00280 assert(hit_item);
00281 hit_item->receiveHit(item_num, (dir+4)%8, 0, 0);
00282 doHitSpecial(hit_item);
00283 }
00284 }
00285 }
00286
00287 sint32 x,y,z,x2,y2,z2;
00288 a->getLocation(x,y,z);
00289 tracker->getInterpolatedPosition(x2,y2,z2,repeatcounter);
00290 if (x == x2 && y == y2 && z == z2) {
00291 tracker->getInterpolatedPosition(x,y,z,repeatcounter+1);
00292 a->collideMove(x, y, z, false, true);
00293 a->setFrame(tracker->getFrame());
00294 } else {
00295 #ifdef WATCHACTOR
00296 if (item_num == watchactor) {
00297 pout << "Animation [" << Kernel::get_instance()->getFrameNum()
00298 << "] moved, so aborting this frame." << std::endl;
00299 }
00300 #endif
00301 }
00302
00303
00304 if (!(a->getFlags() & Item::FLG_FASTAREA)) {
00305 #ifdef WATCHACTOR
00306 if (item_num == watchactor)
00307 pout << "Animation ["
00308 << Kernel::get_instance()->getFrameNum()
00309 << "] ActorAnimProcess left fastarea; terminating"
00310 << std::endl;
00311 #endif
00312 terminate();
00313 return true;
00314 }
00315
00316 #ifdef WATCHACTOR
00317 if (item_num == watchactor) {
00318 pout << "Animation [" << Kernel::get_instance()->getFrameNum()
00319 << "] showing frame (" << x << "," << y << "," << z << ")"
00320 << " shape (" << a->getShape() << "," << tracker->getFrame()
00321 << ") sfx " << tracker->getAnimFrame()->sfx
00322 << " rep " << repeatcounter << " ";
00323
00324 if (tracker->isDone()) pout << "D";
00325 if (tracker->isBlocked()) pout << "B";
00326 if (tracker->isUnsupported()) pout << "U";
00327 if (tracker->hitSomething()) pout << "H";
00328 pout << std::endl;
00329 }
00330 #endif
00331
00332
00333 if (repeatcounter == tracker->getAnimAction()->framerepeat) {
00334 if (tracker->isUnsupported()) {
00335 animAborted = true;
00336
00337 #ifdef WATCHACTOR
00338 if (item_num == watchactor) {
00339 pout << "Animation [" << Kernel::get_instance()->getFrameNum()
00340 << "] falling" << std::endl;
00341 }
00342 #endif
00343
00344 sint32 dx,dy,dz;
00345 tracker->getSpeed(dx,dy,dz);
00346 a->hurl(dx,dy,dz,2);
00347
00348
00349
00350 return true;
00351 }
00352 }
00353
00354 return true;
00355 }
00356
00357 void ActorAnimProcess::doSpecial()
00358 {
00359 Actor *a = getActor(item_num);
00360 assert(a);
00361
00362
00363 if (item_num == 1 && (action == Animation::readyWeapon ||
00364 action == Animation::unreadyWeapon) &&
00365 a->getEquip(ShapeInfo::SE_WEAPON) != 0)
00366 {
00367 int sfx = (std::rand() % 2) ? 0x51 : 0x52;
00368 AudioProcess* audioproc = AudioProcess::get_instance();
00369 if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0);
00370 return;
00371 }
00372
00373
00374 if (a->getShape() == 0x19b)
00375 {
00376 Actor* hostile = 0;
00377 if (action == Animation::attack) {
00378
00379 unsigned int skullcount = a->countNearby(0x19d, 6*256);
00380 if (skullcount > 5) return;
00381
00382 Actor* skull = Actor::createActor(0x19d, 0);
00383 if (!skull) return;
00384 skull->setFlag(Item::FLG_FAST_ONLY);
00385 sint32 x,y,z;
00386 a->getLocation(x,y,z);
00387 int dir = a->getDir();
00388 skull->move(x+32*x_fact[dir],y+32*y_fact[dir],z);
00389 hostile = skull;
00390 } else if (a->getMapNum() != 54) {
00391
00392 unsigned int ghoulcount = a->countNearby(0x8e, 8*256);
00393 if (ghoulcount > 2) return;
00394
00395 sint32 x,y,z;
00396 a->getLocation(x,y,z);
00397 x += (std::rand() % (6*256)) - 3*256;
00398 y += (std::rand() % (6*256)) - 3*256;
00399
00400 Actor* ghoul = Actor::createActor(0x8e, 0);
00401 if (!ghoul) return;
00402 ghoul->setFlag(Item::FLG_FAST_ONLY);
00403 if (!ghoul->canExistAt(x,y,z,true)) {
00404 ghoul->destroy();
00405 return;
00406 }
00407 ghoul->move(x,y,z);
00408 ghoul->doAnim(Animation::standUp, 0);
00409 hostile = ghoul;
00410 }
00411
00412 if (hostile) {
00413 hostile->setInCombat();
00414 CombatProcess* hostilecp = hostile->getCombatProcess();
00415 CombatProcess* cp = a->getCombatProcess();
00416 if (hostilecp && cp)
00417 hostilecp->setTarget(cp->getTarget());
00418 }
00419
00420 return;
00421 }
00422
00423
00424 if (a->getShape() == 0x19d)
00425 {
00426 Actor* av = getMainActor();
00427 if (a->getRange(*av) < 96) {
00428 a->setActorFlag(Actor::ACT_DEAD);
00429 a->explode();
00430 }
00431 return;
00432 }
00433
00434
00435 SettingManager* settingman = SettingManager::get_instance();
00436 bool playavfootsteps;
00437 settingman->get("footsteps", playavfootsteps);
00438 if (item_num != 1 || playavfootsteps)
00439 {
00440 UCList itemlist(2);
00441 LOOPSCRIPT(script, LS_TOKEN_TRUE);
00442 CurrentMap* cm = World::get_instance()->getCurrentMap();
00443
00444
00445 cm->surfaceSearch(&itemlist, script, sizeof(script), a, false, true);
00446 if (itemlist.getSize() == 0) return;
00447
00448 Item* f = getItem(itemlist.getuint16(0));
00449 assert(f);
00450
00451 uint32 floor = f->getShape();
00452 bool running = (action == Animation::run);
00453 bool splash = false;
00454 int sfx = 0;
00455 switch (floor) {
00456 case 0x03: case 0x04: case 0x09: case 0x0B: case 0x5C: case 0x5E:
00457 sfx = 0x2B;
00458 break;
00459 case 0x7E: case 0x80:
00460 sfx = 0xCD;
00461 splash = true;
00462 break;
00463 case 0xA1: case 0xA2: case 0xA3: case 0xA4:
00464 sfx = (running ? 0x99 : 0x91);
00465 break;
00466 default:
00467 sfx = (running ? 0x97 : 0x90);
00468 break;
00469 }
00470
00471 if (sfx) {
00472 AudioProcess* audioproc = AudioProcess::get_instance();
00473 if (audioproc) audioproc->playSFX(sfx, 0x60, item_num, 0, false, 0x10000 + (std::rand()&0x1FFF) - 0x1000);
00474 }
00475
00476 if (splash) {
00477 sint32 x,y,z;
00478 a->getLocation(x,y,z);
00479 Process *sp = new SpriteProcess(475, 0, 7, 1, 1, x, y, z);
00480 Kernel::get_instance()->addProcess(sp);
00481 }
00482 }
00483
00484 }
00485
00486
00487 void ActorAnimProcess::doHitSpecial(Item* hit)
00488 {
00489 Actor *a = getActor(item_num);
00490 assert(a);
00491
00492 Actor* attacked = p_dynamic_cast<Actor*>(hit);
00493
00494 if (item_num == 1 && action == Animation::attack) {
00495
00496
00497 AudioProcess* audioproc = AudioProcess::get_instance();
00498
00499 MainActor* av = getMainActor();
00500 ObjId weaponid = av->getEquip(ShapeInfo::SE_WEAPON);
00501 Item* weapon = getItem(weaponid);
00502
00503 if (!weapon) return;
00504
00505 uint32 weaponshape = weapon->getShape();
00506
00507 switch (weaponshape) {
00508 case 0x32F:
00509 if (audioproc) audioproc->playSFX(23, 0x60, 1, 0, false,
00510 0x10000 + (std::rand()&0x1FFF) - 0x1000);
00511 break;
00512 case 0x330:
00513 {
00514
00515 if (attacked && (attacked->getActorFlags() & Actor::ACT_DEAD)) {
00516
00517 PaletteFaderProcess::I_lightningBolt(0, 0);
00518 int sfx;
00519 switch (std::rand() % 3) {
00520 case 0: sfx = 91; break;
00521 case 1: sfx = 94; break;
00522 default: sfx = 96; break;
00523 }
00524 if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0);
00525 }
00526 break;
00527 }
00528 case 0x331:
00529 {
00530 int sfx = 33;
00531 if (std::rand()%2 == 0) sfx = 101;
00532 if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0, false,
00533 0x10000 + (std::rand()&0x1FFF) - 0x1000);
00534
00535 sint32 x,y,z;
00536 a->getLocation(x,y,z);
00537
00538
00539
00540
00541
00542 Kernel* kernel = Kernel::get_instance();
00543
00544 sint32 fx,fy,fz;
00545 fx = x + 96 * x_fact[dir];
00546 fy = y + 96 * y_fact[dir];
00547 fz = z;
00548
00549
00550
00551 SpriteProcess* sp1 = new SpriteProcess(480, 0, 9, 1, 2, fx,fy,fz);
00552 kernel->addProcess(sp1);
00553
00554 DelayProcess* dp1 = new DelayProcess(3);
00555 ProcId dp1id = kernel->addProcess(dp1);
00556
00557 CreateItemProcess* cip = new CreateItemProcess(400, 0, 0,
00558 Item::FLG_FAST_ONLY,
00559 0, 0, 0, fx,fy,fz);
00560 ProcId cipid = kernel->addProcess(cip);
00561
00562 DelayProcess* dp2 = new DelayProcess(60 + (std::rand()%60));
00563 ProcId dp2id = kernel->addProcess(dp2);
00564
00565 DestroyItemProcess* dip = new DestroyItemProcess(0);
00566 kernel->addProcess(dip);
00567
00568 SpriteProcess* sp2 = new SpriteProcess(381, 0, 9, 1, 1,
00569 fx,fy,fz, true);
00570 kernel->addProcess(sp2);
00571
00572 cip->waitFor(dp1id);
00573 dp2->waitFor(cipid);
00574 dip->waitFor(dp2id);
00575 sp2->waitFor(dp2id);
00576
00577 break;
00578 }
00579 default:
00580 break;
00581 }
00582
00583 return ;
00584 }
00585
00586 }
00587
00588
00589
00590 void ActorAnimProcess::terminate()
00591 {
00592 #ifdef WATCHACTOR
00593 if (item_num == watchactor)
00594 pout << "Animation ["
00595 << Kernel::get_instance()->getFrameNum()
00596 << "] ActorAnimProcess terminating"
00597 << std::endl;
00598 #endif
00599 Actor *a = getActor(item_num);
00600 if (a) {
00601 if (tracker) {
00602 a->clearActorFlag(Actor::ACT_ANIMLOCK);
00603 if (tracker->getAnimAction()->flags & AnimAction::AAF_DESTROYACTOR)
00604 {
00605
00606 #ifdef WATCHACTOR
00607 if (item_num == watchactor)
00608 pout << "Animation ["
00609 << Kernel::get_instance()->getFrameNum()
00610 << "] ActorAnimProcess destroying actor " << item_num
00611 << std::endl;
00612 #endif
00613 Process* vanishproc = new DestroyItemProcess(a);
00614 Kernel::get_instance()->addProcess(vanishproc);
00615
00616 return;
00617 }
00618 }
00619 }
00620
00621 delete tracker;
00622
00623 Process::terminate();
00624 }
00625
00626 void ActorAnimProcess::dumpInfo()
00627 {
00628 Process::dumpInfo();
00629 pout << "action: " << action << ", dir: " << dir << std::endl;
00630 }
00631
00632 void ActorAnimProcess::saveData(ODataSource* ods)
00633 {
00634 Process::saveData(ods);
00635
00636 uint8 ff = firstframe ? 1 : 0;
00637 ods->write1(ff);
00638 uint8 ab = animAborted ? 1 : 0;
00639 ods->write1(ab);
00640 uint8 attacked = attackedSomething ? 1 : 0;
00641 ods->write1(attacked);
00642 ods->write1(static_cast<uint8>(dir));
00643 ods->write2(static_cast<uint16>(action));
00644 ods->write2(static_cast<uint16>(steps));
00645 ods->write2(static_cast<uint16>(repeatcounter));
00646 ods->write2(static_cast<uint16>(currentstep));
00647
00648 if (tracker) {
00649 ods->write1(1);
00650 tracker->save(ods);
00651 } else
00652 ods->write1(0);
00653 }
00654
00655 bool ActorAnimProcess::loadData(IDataSource* ids, uint32 version)
00656 {
00657 if (!Process::loadData(ids, version)) return false;
00658
00659 firstframe = (ids->read1() != 0);
00660 animAborted = (ids->read1() != 0);
00661 attackedSomething = (ids->read1() != 0);
00662 dir = ids->read1();
00663 action = static_cast<Animation::Sequence>(ids->read2());
00664 steps = ids->read2();
00665 repeatcounter = ids->read2();
00666 currentstep = ids->read2();
00667
00668 assert(tracker == 0);
00669 if (ids->read1() != 0) {
00670 tracker = new AnimationTracker();
00671 if (!tracker->load(ids, version))
00672 return false;
00673 }
00674
00675 return true;
00676 }