ActorAnimProcess.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2007 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 //#define WATCHACTOR 1
00052 
00053 #ifdef WATCHACTOR
00054 static const int watchactor = WATCHACTOR;
00055 #endif
00056 
00057 // p_dynamic_cast stuff
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; // CONSTANT !
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                 // invalid direction
00094                 return false;
00095         }
00096 
00097         if (!(actor->getFlags() & Item::FLG_FASTAREA)) {
00098                 // not in the fast area? Can't play an animation then.
00099                 // (If we do, the actor will likely fall because the floor is gone.)
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                 // for now, just don't play this one.
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 /*framenum*/)
00140 {
00141         if (firstframe) {
00142                 bool ret = init();
00143                 if (!ret) {
00144                         // initialization failed
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                 // actor gone
00165                 terminate();
00166                 return false;
00167         }
00168 
00169         firstframe = false;
00170 
00171         if (!(a->getFlags() & Item::FLG_FASTAREA)) {
00172                 // not in the fast area? Kill the animation then.
00174                 //  Animation could do one of three things: pause, move
00175                 //  without allowing actor to fall, or pretend to move and
00176                 //  complete the entire movement as the actor reappears
00177                 //  in fast area (still may need to pause when
00178                 //  AnimationTracker is done.)
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                 // next step:
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                         // check possible error conditions
00201 
00202                         if (tracker->isDone() || (steps && currentstep >= steps) ) {
00203                                 // all done
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                                 // TODO: there are _three_ places where we can fall; clean up
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                                         // no inertia here because we just crashed into something
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                         // Flag to trigger a special action
00268                         // E.g.: play draw/sheathe SFX for avatar when weapon equipped,
00269                         // throw skull-fireball when ghost attacks, ...
00270                         doSpecial();
00271                 }
00272 
00273 
00274                 // attacking?
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); // forced move
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         // Did we just leave the fast area?
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                         // Note: do not wait for the fall to finish: this breaks
00349                         // the scene where Devon kills Mordea
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         // play SFX when Avatar draws/sheathes weapon
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; // constants!
00368                 AudioProcess* audioproc = AudioProcess::get_instance();
00369                 if (audioproc) audioproc->playSFX(sfx, 0x60, 1, 0);
00370                 return;
00371         }
00372 
00373         // ghosts
00374         if (a->getShape() == 0x19b)
00375         {
00376                 Actor* hostile = 0;
00377                 if (action == Animation::attack) {
00378                         // fireball on attack
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) { // Khumash-Gor doesn't summon ghouls
00391                         // otherwise, summon ghoul
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         // ghost's fireball
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(); // explode if close to the avatar
00430                 }
00431                 return;
00432         }
00433 
00434         // play PC/NPC footsteps
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                 // find items directly below
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) { // lots of constants!!
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                 // some magic weapons have some special effects
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: // magic hammer
00509                         if (audioproc) audioproc->playSFX(23, 0x60, 1, 0, false,
00510                                                                   0x10000 + (std::rand()&0x1FFF) - 0x1000);
00511                         break;
00512                 case 0x330: // Slayer
00513                 {
00514                         // if we killed somebody, thunder&lightning
00515                         if (attacked && (attacked->getActorFlags() & Actor::ACT_DEAD)) {
00516                                 // calling intrinsic...
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: // Flame Sting
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                         // 1: create flame sprite
00538                         // 2: create flame object
00539                         // 3: wait
00540                         // 4a: destroy flame object
00541                         // 4b: create douse-flame sprite
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                         // CONSTANTS!! (lots of them)
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)); //2-4s
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) { // if we were really animating...
00602                         a->clearActorFlag(Actor::ACT_ANIMLOCK);
00603                         if (tracker->getAnimAction()->flags & AnimAction::AAF_DESTROYACTOR)
00604                         {
00605                                 // destroy the actor
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 }

Generated on Fri Jul 27 22:27:09 2007 for pentagram by  doxygen 1.4.7