Actor.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 #include "Actor.h"
00021 
00022 #include "ObjectManager.h"
00023 #include "Kernel.h"
00024 #include "UCMachine.h"
00025 #include "UCList.h"
00026 #include "World.h"
00027 #include "ActorAnimProcess.h"
00028 #include "AnimationTracker.h"
00029 #include "CurrentMap.h"
00030 #include "Direction.h"
00031 #include "GameData.h"
00032 #include "MainShapeArchive.h"
00033 #include "AnimAction.h"
00034 #include "ShapeInfo.h"
00035 #include "Pathfinder.h"
00036 #include "Animation.h"
00037 #include "DelayProcess.h"
00038 #include "ResurrectionProcess.h"
00039 #include "DestroyItemProcess.h"
00040 #include "ClearFeignDeathProcess.h"
00041 #include "PathfinderProcess.h"
00042 #include "Shape.h"
00043 #include "LoiterProcess.h"
00044 #include "CombatProcess.h"
00045 #include "AudioProcess.h"
00046 #include "SpriteProcess.h"
00047 #include "MainActor.h"
00048 #include "MusicProcess.h"
00049 #include "getObject.h"
00050 
00051 #include "ItemFactory.h"
00052 #include "LoopScript.h"
00053 #include "IDataSource.h"
00054 #include "ODataSource.h"
00055 
00056 // p_dynamic_cast stuff
00057 DEFINE_RUNTIME_CLASSTYPE_CODE(Actor,Container);
00058 
00059 Actor::Actor()
00060         : strength(0), dexterity(0), intelligence(0),
00061           hitpoints(0), mana(0), alignment(0), enemyalignment(0),
00062           lastanim(Animation::walk), animframe(0), direction(0),
00063           fallstart(0), unk0C(0), actorflags(0)
00064 {
00065 
00066 }
00067 
00068 Actor::~Actor()
00069 {
00070 
00071 }
00072 
00073 uint16 Actor::assignObjId()
00074 {
00075         if (objid == 0xFFFF)
00076                 objid = ObjectManager::get_instance()->assignActorObjId(this);
00077 
00078         std::list<Item*>::iterator iter;
00079         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00080                 (*iter)->assignObjId();
00081                 (*iter)->setParent(objid);
00082         }
00083 
00084         return objid;
00085 }
00086 
00087 sint16 Actor::getMaxMana() const
00088 {
00089         return static_cast<sint16>(2 * getInt());
00090 }
00091 
00092 uint16 Actor::getMaxHP() const
00093 {
00094         return static_cast<uint16>(2 * getStr());
00095 }
00096 
00097 bool Actor::loadMonsterStats()
00098 {
00099         ShapeInfo* shapeinfo = getShapeInfo();
00100         MonsterInfo* mi = 0;
00101         if (shapeinfo) mi = shapeinfo->monsterinfo;
00102         if (!mi)
00103                 return false;
00104 
00105         uint16 hp;
00106         if (mi->max_hp <= mi->min_hp)
00107                 hp = mi->min_hp;
00108         else
00109                 hp = mi->min_hp + std::rand() % (mi->max_hp - mi->min_hp);
00110         setHP(hp);
00111         
00112         uint16 dex;
00113         if (mi->max_dex <= mi->min_dex)
00114                 dex = mi->min_dex;
00115         else
00116                 dex = mi->min_dex + std::rand() % (mi->max_dex - mi->min_dex);
00117         setDex(dex);
00118         
00119         uint8 alignment = mi->alignment;
00120         setAlignment(alignment & 0x0F);
00121         setEnemyAlignment((alignment & 0xF0) >> 4); // !! CHECKME
00122 
00123         return true;
00124 }
00125 
00126 bool Actor::giveTreasure()
00127 {
00128         MainShapeArchive* mainshapes = GameData::get_instance()->getMainShapes();
00129         ShapeInfo* shapeinfo = getShapeInfo();
00130         MonsterInfo* mi = 0;
00131         if (shapeinfo) mi = shapeinfo->monsterinfo;
00132         if (!mi)
00133                 return false;
00134 
00135         std::vector<TreasureInfo>& treasure = mi->treasure;
00136 
00137         for (unsigned int i = 0; i < treasure.size(); ++i) {
00138                 TreasureInfo& ti = treasure[i];
00139                 Item* item;
00140 
00141                 // check map
00142                 int currentmap = World::get_instance()->getCurrentMap()->getNum();
00143                 if (ti.map != 0 && ((ti.map > 0 && ti.map != currentmap) ||
00144                                                         (ti.map < 0 && -ti.map == currentmap)))
00145                 {
00146                         continue;
00147                 }
00148 
00149                 // check chance
00150                 if (ti.chance < 0.999 &&
00151                         (static_cast<double>(std::rand()) / RAND_MAX) > ti.chance)
00152                 {
00153                         continue;
00154                 }
00155 
00156                 // determine count/quantity
00157                 int count;
00158                 if (ti.mincount >= ti.maxcount)
00159                         count = ti.mincount;
00160                 else
00161                         count = ti.mincount + (std::rand() % (ti.maxcount - ti.mincount));
00162 
00163                 if (!ti.special.empty()) {
00164                         if (ti.special == "weapon") {
00165 
00166                                 // NB: this is rather biased towards weapons with low shapes...
00167                                 for (unsigned int s = 0; s < mainshapes->getCount(); ++s) {
00168                                         ShapeInfo* si = mainshapes->getShapeInfo(s);
00169                                         if (!si->weaponinfo) continue;
00170 
00171                                         int chance = si->weaponinfo->treasure_chance;
00172                                         if (!chance) continue;
00173 
00174                                         int r = std::rand() % 100;
00175 #if 0
00176                                         pout << "weapon (" << s << ") chance: " << r << "/"
00177                                                  << chance << std::endl;
00178 #endif
00179                                         if (r >= chance) continue;
00180 
00181                                         // create the weapon
00182                                         item = ItemFactory::createItem(s,
00183                                                                                                    0, // frame
00184                                                                                                    count, // quality
00185                                                                                                    Item::FLG_DISPOSABLE,//flags
00186                                                                                                    0, // npcnum,
00187                                                                                                    0, // mapnum
00188                                                                                                    0, true); // ext.flags,objid
00189                                         item->moveToContainer(this);
00190                                         item->randomGumpLocation();
00191                                         break;
00192                                 }
00193                         } else if (ti.special == "sorcfocus") {
00194                                 // CONSTANTS! (and lots of them...)
00195                                 int shape = 397;
00196                                 int frame;
00197                                 uint16 quality;
00198 
00199                                 if (std::rand() % 10 < 8)
00200                                 {
00201                                         // wand
00202                                         if (std::rand() % 10 < 4) {
00203                                                 // charged
00204                                                 frame = 0;
00205                                                 quality = 3 + (std::rand() % 4) + // charges
00206                                                         ((1 + (std::rand()%4))<<8);   // spell
00207                                         } else {
00208                                                 frame = 15;
00209                                                 quality = 0;
00210                                         }
00211 
00212                                         item = ItemFactory::createItem(shape, frame, quality,
00213                                                                                                    Item::FLG_DISPOSABLE,
00214                                                                                                    0, 0, 0, true);
00215                                         item->moveToContainer(this);
00216                                         item->randomGumpLocation();
00217                                 }
00218 
00219                                 if (std::rand() % 10 < 6)
00220                                 {
00221                                         // rod
00222                                         if (std::rand() % 10 < 2) {
00223                                                 // charged
00224                                                 frame = 3;
00225                                                 quality = 3 + (std::rand() % 4) + // charges
00226                                                         ((1 + (std::rand()%7))<<8);   // spell
00227                                         } else {
00228                                                 frame = 16;
00229                                                 quality = 0;
00230                                         }
00231 
00232                                         item = ItemFactory::createItem(shape, frame, quality,
00233                                                                                                    Item::FLG_DISPOSABLE,
00234                                                                                                    0, 0, 0, true);
00235                                         item->moveToContainer(this);
00236                                         item->randomGumpLocation();
00237                                 }
00238 
00239                                 if (std::rand() % 10 < 5)
00240                                 {
00241                                         // symbol
00242                                         if (std::rand() % 10 < 5) {
00243                                                 // charged
00244                                                 frame = 12;
00245                                                 uint8 spell = 1 + (std::rand()%11);
00246                                                 quality = spell<<8;
00247                                                 if (spell < 4) {
00248                                                         quality += 3 + (std::rand()%4);
00249                                                 } else {
00250                                                         // symbol can only have one charge of anything
00251                                                         // other than ignite/extinguish
00252                                                         quality += 1;
00253                                                 }
00254                                         } else {
00255                                                 frame = 19;
00256                                                 quality = 0;
00257                                         }
00258 
00259                                         item = ItemFactory::createItem(shape, frame, quality,
00260                                                                                                    Item::FLG_DISPOSABLE,
00261                                                                                                    0, 0, 0, true);
00262                                         item->moveToContainer(this);
00263                                         item->randomGumpLocation();
00264                                 }
00265 
00266                                 if (std::rand() % 10 < 2)
00267                                 {
00268                                         // demon talisman
00269                                         if (std::rand() % 10 < 2) {
00270                                                 // charged
00271                                                 frame = 9;
00272                                                 quality = 1 + (std::rand() % 2) +  // charges
00273                                                         ((10 + (std::rand()%2))<<8);   // spell
00274                                         } else {
00275                                                 frame = 18;
00276                                                 quality = 0;
00277                                         }
00278 
00279                                         item = ItemFactory::createItem(shape, frame, quality,
00280                                                                                                    Item::FLG_DISPOSABLE,
00281                                                                                                    0, 0, 0, true);
00282                                         item->moveToContainer(this);
00283                                         item->randomGumpLocation();
00284                                 }
00285 
00286                         } else {
00287                                 pout << "Unhandled special treasure: " << ti.special
00288                                          << std::endl;
00289                         }
00290                         continue;
00291                 }
00292 
00293                 // if shapes.size() == 1 and the given shape is SF_QUANTITY,
00294                 // then produce a stack of that shape (ignoring frame)
00295 
00296                 if (ti.shapes.size() == 1) {
00297                         uint32 shape = ti.shapes[0];
00298                         ShapeInfo* si = mainshapes->getShapeInfo(shape);
00299                         if (!si) {
00300                                 perr << "Trying to create treasure with an invalid shape ("
00301                                          << shape << ")" << std::endl;
00302                                 continue;
00303                         }
00304                         if (si->hasQuantity()) {
00305                                 // CHECKME: which flags?
00306                                 item = ItemFactory::createItem(shape,
00307                                                                                            0, // frame
00308                                                                                            count, // quality
00309                                                                                            Item::FLG_DISPOSABLE, // flags
00310                                                                                            0, // npcnum,
00311                                                                                            0, // mapnum
00312                                                                                            0, true); // ext. flags, objid
00313                                 item->moveToContainer(this);
00314                                 item->randomGumpLocation();
00315                                 item->callUsecodeEvent_combine(); // this sets the right frame
00316                                 continue;
00317                         }
00318                 }
00319 
00320                 if (ti.shapes.empty() || ti.frames.empty()) {
00321                         perr << "No shape/frame set in treasure" << std::endl;
00322                         continue;
00323                 }
00324 
00325                 // we need to produce a number of items
00326                 for (int i = 0; i < count; ++i) {
00327                         // pick shape
00328                         int n = std::rand() % ti.shapes.size();
00329                         uint32 shape = ti.shapes[n];
00330 
00331                         // pick frame
00332                         n = std::rand() % ti.frames.size();
00333                         uint32 frame = ti.frames[n];
00334 
00335                         ShapeInfo* si = GameData::get_instance()->getMainShapes()->
00336                                 getShapeInfo(shape);
00337                         if (!si) {
00338                                 perr << "Trying to create treasure with an invalid shape ("
00339                                          << shape << ")" << std::endl;
00340                                 continue;
00341                         }
00342                         uint16 qual = 0;
00343                         if (si->hasQuantity())
00344                                 qual = 1;
00345 
00346                         // CHECKME: flags?
00347                         item = ItemFactory::createItem(shape,
00348                                                                                    frame, // frame
00349                                                                                    qual, // quality
00350                                                                                    Item::FLG_DISPOSABLE, // flags
00351                                                                                    0, // npcnum,
00352                                                                                    0, // mapnum
00353                                                                                    0, true); // ext. flags, objid
00354                         item->moveToContainer(this);
00355                         item->randomGumpLocation();
00356                 }
00357         }
00358 
00359         return true;
00360 }
00361 
00362 bool Actor::removeItem(Item* item)
00363 {
00364         if (!Container::removeItem(item)) return false;
00365 
00366         item->clearFlag(FLG_EQUIPPED); // unequip if necessary
00367 
00368         return true;
00369 }
00370 
00371 bool Actor::setEquip(Item* item, bool checkwghtvol)
00372 {
00373         const unsigned int backpack_shape = 529; 
00374         uint32 equiptype = item->getShapeInfo()->equiptype;
00375         bool backpack = (item->getShape() == backpack_shape);
00376 
00377         // valid item type?
00378         if (equiptype == ShapeInfo::SE_NONE && !backpack) return false;
00379 
00380         // now check 'equipment slots'
00381         // we can have one item of each equipment type, plus one backpack
00382         std::list<Item*>::iterator iter;
00383         for (iter = contents.begin(); iter != contents.end(); ++iter)
00384         {
00385                 if ((*iter)->getObjId() == item->getObjId()) continue;
00386 
00387                 uint32 cet = (*iter)->getShapeInfo()->equiptype;
00388                 bool cbackpack = ((*iter)->getShape() == backpack_shape);
00389 
00390                 // already have an item with the same equiptype
00391                 if (cet == equiptype || (cbackpack && backpack)) return false;
00392         }
00393 
00394         if (!item->moveToContainer(this, checkwghtvol)) return false;
00395         item->clearFlag(FLG_CONTAINED);
00396         item->setFlag(FLG_EQUIPPED);
00397         item->setZ(equiptype);
00398 
00399         return true;
00400 }
00401 
00402 uint16 Actor::getEquip(uint32 type)
00403 {
00404         const unsigned int backpack_shape = 529; 
00405 
00406         std::list<Item*>::iterator iter;
00407         for (iter = contents.begin(); iter != contents.end(); ++iter)
00408         {
00409                 uint32 cet = (*iter)->getShapeInfo()->equiptype;
00410                 bool cbackpack = ((*iter)->getShape() == backpack_shape);
00411 
00412                 if (((*iter)->getFlags() & FLG_EQUIPPED) &&
00413                         (cet == type || (cbackpack && type == 7))) // !! constant
00414                 {
00415                         return (*iter)->getObjId();
00416                 }
00417         }
00418 
00419         return 0;
00420 }
00421 
00422 void Actor::teleport(int newmap, sint32 newx, sint32 newy, sint32 newz)
00423 {
00424         uint16 newmapnum = static_cast<uint16>(newmap);
00425 
00426         // Set the mapnum
00427         setMapNum(newmapnum);
00428 
00429         // Put it in the void
00430         moveToEtherealVoid();
00431 
00432         // Move it to this map
00433         if (newmapnum == World::get_instance()->getCurrentMap()->getNum())
00434         {
00435 #ifdef DEBUG
00436                 perr << "Actor::teleport: " << getObjId() << " to " << newmap << ","
00437                          << newx << "," << newy << "," << newz << std::endl;
00438 #endif
00439                 move(newx, newy, newz);
00440         }
00441         // Move it to another map
00442         else
00443         {
00444                 World::get_instance()->etherealRemove(objid);
00445                 x = newx;
00446                 y = newy;
00447                 z = newz;
00448         }
00449 } 
00450 
00451 uint16 Actor::doAnim(Animation::Sequence anim, int dir, unsigned int steps)
00452 {
00453         if (dir < 0 || dir > 8) {
00454                 perr << "Actor::doAnim: Invalid direction (" << dir << ")" <<std::endl;
00455                 return 0;
00456         }
00457 
00458 #if 0
00459         if (tryAnim(anim, dir)) {
00460                 perr << "Actor::doAnim: tryAnim = Ok!" << std::endl;
00461         } else {
00462                 perr << "Actor::doAnim: tryAnim = bad!" << std::endl;
00463         }
00464 #endif
00465 
00466         Process *p = new ActorAnimProcess(this, anim, dir, steps);
00467 
00468         return Kernel::get_instance()->addProcess(p);
00469 }
00470 
00471 bool Actor::hasAnim(Animation::Sequence anim)
00472 {
00473         AnimationTracker tracker;
00474 
00475         return tracker.init(this, anim, 0);
00476 }
00477 
00478 Animation::Result Actor::tryAnim(Animation::Sequence anim, int dir,
00479                                                                  unsigned int steps, PathfindingState* state)
00480 {
00481         if (dir < 0 || dir > 8) return Animation::FAILURE;
00482 
00483         if (dir == 8) dir = getDir();
00484 
00485         AnimationTracker tracker;
00486         if (!tracker.init(this, anim, dir, state))
00487                 return Animation::FAILURE;
00488 
00489         AnimAction * animaction = tracker.getAnimAction();
00490 
00491         if (!animaction) return Animation::FAILURE;
00492 
00493         unsigned int curstep = 0;
00494 
00495         while (tracker.step() && (!steps || curstep >= steps))
00496         {
00497                 curstep++;
00498         }
00499 
00500         if (tracker.isBlocked() &&
00501                 !(animaction->flags & AnimAction::AAF_UNSTOPPABLE))
00502         {
00503                 return Animation::FAILURE;
00504         }
00505 
00506         if (state) {
00507                 tracker.updateState(*state);
00508                 state->lastanim = anim;
00509                 state->direction = dir;
00510         }
00511 
00512 
00513         if (tracker.isUnsupported())
00514         {
00515                 return Animation::END_OFF_LAND;
00516         }
00517 
00518         // isUnsupported only checks for AFF_ONGROUND, we need either
00519         sint32 end[3], dims[3];
00520         getFootpadWorld(dims[0], dims[1], dims[2]);
00521         tracker.getPosition(end[0], end[1], end[2]);
00522 
00523         CurrentMap * cm = World::get_instance()->getCurrentMap();
00524 
00525         UCList uclist(2);
00526         LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
00527         cm->surfaceSearch(&uclist, script, sizeof(script),
00528                                           getObjId(), end, dims,
00529                                           false, true, false);
00530         for (uint32 i = 0; i < uclist.getSize(); i++)
00531         {
00532                 Item *item = getItem(uclist.getuint16(i));
00533                 if (item->getShapeInfo()->is_land())
00534                         return Animation::SUCCESS;
00535         }
00536 
00537         return Animation::END_OFF_LAND;
00538 }
00539 
00540 uint16 Actor::cSetActivity(int activity)
00541 {
00542         switch (activity) {
00543         case 0: // loiter
00544                 Kernel::get_instance()->addProcess(new LoiterProcess(this));
00545                 return Kernel::get_instance()->addProcess(new DelayProcess(1));
00546                 break;
00547         case 1: // combat
00548                 setInCombat();
00549                 return 0;
00550         case 2: // stand
00551                 // NOTE: temporary fall-throughs!
00552                 return doAnim(Animation::stand, 8);
00553 
00554         default:
00555                 perr << "Actor::cSetActivity: invalid activity (" << activity << ")"
00556                          << std::endl;
00557         }
00558 
00559         return 0;
00560 }
00561 
00562 uint32 Actor::getArmourClass()
00563 {
00564         ShapeInfo* si = getShapeInfo();
00565         if (si->monsterinfo)
00566                 return si->monsterinfo->armour_class;
00567         else
00568                 return 0;
00569 }
00570 
00571 uint16 Actor::getDefenseType()
00572 {
00573         ShapeInfo* si = getShapeInfo();
00574         if (si->monsterinfo)
00575                 return si->monsterinfo->defense_type;
00576         else
00577                 return 0;
00578 }
00579 
00580 sint16 Actor::getDefendingDex()
00581 {
00582         return getDex();
00583 }
00584 
00585 sint16 Actor::getAttackingDex()
00586 {
00587         return getDex();
00588 }
00589 
00590 uint16 Actor::getDamageType()
00591 {
00592         ShapeInfo* si = getShapeInfo();
00593         if (si->monsterinfo)
00594                 return si->monsterinfo->damage_type;
00595         else 
00596                 return WeaponInfo::DMG_NORMAL;
00597 }
00598 
00599 
00600 int Actor::getDamageAmount()
00601 {
00602         ShapeInfo* si = getShapeInfo();
00603         if (si->monsterinfo) {
00604 
00605                 int min = static_cast<int>(si->monsterinfo->min_dmg);
00606                 int max = static_cast<int>(si->monsterinfo->max_dmg);
00607                 
00608                 int damage = (std::rand() % (max - min + 1)) + min;
00609                 
00610                 return damage;
00611         } else {
00612                 return 1;
00613         }
00614 }
00615 
00616 
00617 void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type)
00618 {
00619         if (isDead())
00620                 return; // already dead, so don't bother
00621 
00622         Item* hitter = getItem(other);
00623         Actor* attacker = getActor(other);
00624 
00625         if (damage == 0 && attacker) {
00626                 damage = attacker->getDamageAmount();
00627         }
00628 
00629         if (damage_type == 0 && hitter) {
00630                 damage_type = hitter->getDamageType();
00631         }
00632 
00633         if (other == 1 && attacker->getLastAnim() != Animation::kick) {
00634                 // strength for kicks is accumulated in AvatarMoverProcess
00635                 MainActor* av = getMainActor();
00636                 av->accumulateStr(damage/4);
00637         }
00638 
00639         pout << "Actor " << getObjId() << " received hit from " << other
00640                  << " (dmg=" << damage << ",type=" << std::hex << damage_type
00641                  << std::dec << "). ";
00642 
00643         damage = calculateAttackDamage(other, damage, damage_type);
00644 
00645         if (!damage) {
00646                 pout << "No damage." << std::endl;
00647         } else {
00648                 pout << "Damage: " << damage << std::endl;
00649         }
00650 
00651         if (damage >= 4 && objid == 1 && attacker) {
00652                 // play blood sprite
00653                 int start = 0, end = 12;
00654                 if (dir > 2) {
00655                         start = 13; end = 25;
00656                 }
00657 
00658                 sint32 x,y,z;
00659                 getLocation(x,y,z);
00660                 z += (std::rand() % 24);
00661                 Process *sp = new SpriteProcess(620, start, end, 1, 1, x, y, z);
00662                 Kernel::get_instance()->addProcess(sp);
00663         }
00664 
00665         if (damage > 0 && !(getActorFlags() & (ACT_IMMORTAL | ACT_INVINCIBLE))) {
00666                 if (damage >= hitpoints) {
00667                         // we're dead
00668 
00669                         if (getActorFlags() & ACT_WITHSTANDDEATH) {
00670                                 // or maybe not...
00671 
00672                                 setHP(getMaxHP());
00673                                 AudioProcess* audioproc = AudioProcess::get_instance();
00674                                 if (audioproc) audioproc->playSFX(59, 0x60, objid, 0);
00675                                 clearActorFlag(ACT_WITHSTANDDEATH);
00676                         } else {
00677                                 die(damage_type);
00678                         }
00679                         return;
00680                 }
00681 
00682                 // not dead yet
00683                 setHP(static_cast<uint16>(hitpoints - damage));
00684         }
00685 
00686         ProcId fallingprocid = 0;
00687         if (objid == 1 && damage > 0) {
00688                 if ((damage_type & WeaponInfo::DMG_FALLING) && damage >= 6) {
00689                         // high falling damage knocks you down
00690                         doAnim(Animation::fallBackwards, 8);
00691 
00692                         // TODO: shake head after getting back up when not in combat
00693                         return;
00694                 }
00695 
00696                 // got hit, so abort current animation
00697                 fallingprocid = killAllButFallAnims(false);
00698         }
00699 
00700         // if avatar was blocking; do a quick stopBlock/startBlock and play SFX
00701         if (objid == 1 && getLastAnim() == Animation::startBlock) {
00702                 ProcId anim1pid = doAnim(Animation::stopBlock, 8);
00703                 ProcId anim2pid = doAnim(Animation::startBlock, 8);
00704 
00705                 Process* anim1proc = Kernel::get_instance()->getProcess(anim1pid);
00706                 Process* anim2proc = Kernel::get_instance()->getProcess(anim2pid);
00707                 assert(anim1proc);
00708                 assert(anim2proc);
00709                 anim2proc->waitFor(anim1proc);
00710 
00711                 int sfx;
00712                 if (damage)
00713                         sfx = 50 + (std::rand() % 2); // constants!
00714                 else
00715                         sfx = 20 + (std::rand() % 3); // constants!
00716                 AudioProcess* audioproc = AudioProcess::get_instance();
00717                 if (audioproc) audioproc->playSFX(sfx, 0x60, objid, 0);
00718                 return;
00719         }
00720 
00721         // TODO: target needs to stumble/fall/call for help/...(?)
00722 
00723         if (objid != 1) {
00724                 ObjId target = 1;
00725                 if (attacker)
00726                         target = attacker->getObjId();
00727                 if (!isInCombat())
00728                         setInCombat();
00729 
00730                 CombatProcess* cp = getCombatProcess();
00731                 assert(cp);
00732                 cp->setTarget(target);
00733 
00734                 if (target == 1) {
00735                         // call for help
00736                 }
00737         }
00738 
00739         if (damage && !fallingprocid) {
00740                 ProcId anim1pid = doAnim(Animation::stumbleBackwards, dir);
00741                 ProcId anim2pid;
00742                 if (isInCombat())
00743                         // not doing this would cause you to re-draw your weapon when hit
00744                         anim2pid = doAnim(Animation::combatStand, dir);
00745                 else
00746                         anim2pid = doAnim(Animation::stand, dir);
00747                 Process* anim1proc = Kernel::get_instance()->getProcess(anim1pid);
00748                 Process* anim2proc = Kernel::get_instance()->getProcess(anim2pid);
00749                 assert(anim1proc);
00750                 assert(anim2proc);
00751                 anim2proc->waitFor(anim1proc);
00752         }
00753 }
00754 
00755 ProcId Actor::die(uint16 damageType)
00756 {
00757         setHP(0);
00758         setActorFlag(ACT_DEAD);
00759         clearActorFlag(ACT_INCOMBAT);
00760 
00761         ProcId animprocid = 0;
00762 #if 1
00763         animprocid = killAllButFallAnims(true);
00764 #else
00765         Kernel::get_instance()->killProcesses(getObjId(), 6, true); // CONSTANT!
00766 #endif
00767 
00768         if (!animprocid)
00769                 animprocid = doAnim(Animation::die, getDir());
00770 
00771 
00772         MainActor* avatar = getMainActor();
00773         // if hostile to avatar
00774         if (getEnemyAlignment() & avatar->getAlignment()) {
00775                 if (avatar->isInCombat()) {
00776                         // play victory fanfare
00777                         MusicProcess::get_instance()->playCombatMusic(109);
00778                         // and resume combat music afterwards
00779                         MusicProcess::get_instance()->queueMusic(98);
00780                 }
00781         }
00782 
00783 
00784         destroyContents();
00785         giveTreasure();
00786 
00787         ShapeInfo* shapeinfo = getShapeInfo();
00788         MonsterInfo* mi = 0;
00789         if (shapeinfo) mi = shapeinfo->monsterinfo;
00790 
00791         if (mi && mi->resurrection && !(damageType & WeaponInfo::DMG_FIRE)) {
00792                 // this monster will be resurrected after a while
00793 
00794                 pout << "Actor::die: scheduling resurrection" << std::endl;
00795 
00796                 int timeout = ((std::rand() % 25) + 5) * 30; // 5-30 seconds
00797 
00798                 Process* resproc = new ResurrectionProcess(this);
00799                 Kernel::get_instance()->addProcess(resproc);
00800 
00801                 Process* delayproc = new DelayProcess(timeout);
00802                 Kernel::get_instance()->addProcess(delayproc);
00803 
00804                 ProcId animpid = doAnim(Animation::standUp, 8);
00805                 Process* animproc = Kernel::get_instance()->getProcess(animpid);
00806                 assert(animproc);
00807 
00808                 resproc->waitFor(delayproc);
00809                 animproc->waitFor(resproc);
00810         }
00811 
00812         if (mi && mi->explode) {
00813                 // this monster explodes when it dies
00814 
00815                 pout << "Actor::die: exploding" << std::endl;
00816 
00817                 int count = 5;
00818                 Shape* explosionshape = GameData::get_instance()->getMainShapes()
00819                         ->getShape(mi->explode);
00820                 assert(explosionshape);
00821                 unsigned int framecount = explosionshape->frameCount();
00822 
00823                 for (int i = 0; i < count; ++i) {
00824                         Item* piece = ItemFactory::createItem(mi->explode,
00825                                                                                                   std::rand()%framecount,
00826                                                                                                   0, // qual
00827                                                                                                   Item::FLG_FAST_ONLY, //flags,
00828                                                                                                   0, // npcnum
00829                                                                                                   0, // mapnum
00830                                                                                                   0, true // ext. flags, objid
00831                                 );
00832                         piece->move(x - 128 + 32*(std::rand()%6),
00833                                                 y - 128 + 32*(std::rand()%6),
00834                                                 z + std::rand()%8 ); // move to near actor's position
00835                         piece->hurl(-25 + (std::rand()%50),
00836                                                 -25 + (std::rand()%50),
00837                                                 10 + (std::rand()%10),
00838                                                 4); // (wrong?) CONSTANTS!
00839                 }
00840         }
00841 
00842         return animprocid;
00843 }
00844 
00845 void Actor::killAllButCombatProcesses()
00846 {
00847         // loop over all processes, keeping only the relevant ones
00848         ProcessIter iter = Kernel::get_instance()->getProcessBeginIterator();
00849         ProcessIter endproc = Kernel::get_instance()->getProcessEndIterator();
00850         for (; iter != endproc; ++iter) {
00851                 Process* p = *iter;
00852                 if (!p) continue;
00853                 if (p->getItemNum() != objid) continue;
00854                 if (p->is_terminated()) continue;
00855 
00856                 uint16 type = p->getType();
00857 
00858                 if (type != 0xF0 && type != 0xF2 && type != 0x208 && type != 0x21D &&
00859                         type != 0x220 && type != 0x238 && type != 0x243)
00860                 {
00861                         p->fail();
00862                 }
00863         }
00864 }
00865 
00866 ProcId Actor::killAllButFallAnims(bool death)
00867 {
00868         ProcId fallproc = 0;
00869 
00870         Kernel* kernel = Kernel::get_instance();
00871 
00872         if (death) {
00873                 // if dead, we want to kill everything but animations
00874                 kernel->killProcessesNotOfType(objid, 0xF0, true);
00875         } else {
00876                 // otherwise, need to focus on combat, so kill everything else
00877                 killAllButCombatProcesses();
00878         }
00879 
00880         // loop over all animation processes, keeping only the relevant ones
00881         ProcessIter iter = Kernel::get_instance()->getProcessBeginIterator();
00882         ProcessIter endproc = Kernel::get_instance()->getProcessEndIterator();
00883         for (; iter != endproc; ++iter) {
00884                 ActorAnimProcess* p = p_dynamic_cast<ActorAnimProcess*>(*iter);
00885                 if (!p) continue;
00886                 if (p->getItemNum() != objid) continue;
00887                 if (p->is_terminated()) continue;
00888 
00889                 Animation::Sequence action = p->getAction();
00890 
00891                 if (action == Animation::die) {
00892                         fallproc = p->getPid();
00893                         continue;
00894                 }
00895 
00896                 if (!death && action == Animation::standUp) {
00897                         fallproc = p->getPid();
00898                 } else {
00899                         p->fail();
00900                 }
00901         }
00902 
00903         return fallproc;
00904 }
00905 
00906 int Actor::calculateAttackDamage(uint16 other, int damage, uint16 damage_type)
00907 {
00908         Actor* attacker = getActor(other);
00909 
00910         uint16 defense_type = getDefenseType();
00911 
00912         // most damage types are blocked straight away by defense types
00913         damage_type &= ~(defense_type & ~(WeaponInfo::DMG_MAGIC  |
00914                                                                           WeaponInfo::DMG_UNDEAD |
00915                                                                           WeaponInfo::DMG_PIERCE));
00916 
00917         // immunity to non-magical weapons
00918         if ((defense_type & WeaponInfo::DMG_MAGIC) &&
00919                 !(damage_type & WeaponInfo::DMG_MAGIC))
00920         {
00921                 damage = 0;
00922         }
00923 
00924         bool slayer = false;
00925 
00926         // special attacks
00927         if (damage && damage_type)
00928         {
00929                 if (damage_type & WeaponInfo::DMG_SLAYER) {
00930                         if (std::rand() % 10 == 0) {
00931                                 slayer = true;
00932                                 damage = 255; // instant kill
00933                         }
00934                 }
00935 
00936                 if ((damage_type & WeaponInfo::DMG_UNDEAD) &&
00937                         (defense_type & WeaponInfo::DMG_UNDEAD))
00938                 {
00939                         damage *= 2; // double damage against undead
00940                 }
00941 
00942                 if ((defense_type & WeaponInfo::DMG_PIERCE) &&
00943                         !(damage_type & (WeaponInfo::DMG_BLADE |
00944                                                          WeaponInfo::DMG_FIRE  |
00945                                                          WeaponInfo::DMG_PIERCE)))
00946                 {
00947                         damage /= 2; // resistance to blunt damage
00948                 }
00949         } else {
00950                 damage = 0;
00951         }
00952 
00953         // armour
00954         if (damage && !(damage_type & WeaponInfo::DMG_PIERCE) && !slayer)
00955         {
00956                 // blocking?
00957                 if ((getLastAnim() == Animation::startBlock ||
00958                          getLastAnim() == Animation::stopBlock) &&
00959                         !(getActorFlags() & ACT_STUNNED))
00960                 {
00961                         damage -= getStr() / 5;
00962                 }
00963 
00964                 int ACmod = 3 * getArmourClass();
00965                 if (damage_type & WeaponInfo::DMG_FIRE)
00966                         ACmod /= 2; // armour doesn't protect from fire as well
00967 
00968                 if (getActorFlags() & ACT_STUNNED)
00969                         ACmod /= 2; // stunned?
00970 
00971                 if (ACmod > 100) ACmod = 100;
00972 
00973                 // TODO: replace rounding bias by something random
00974                 damage = ((100 - ACmod) * damage) / 100;
00975 
00976                 if (damage < 0) damage = 0;
00977         }
00978 
00979         // to-hit
00980         if (damage && !(damage_type & WeaponInfo::DMG_PIERCE) && attacker)
00981         {
00982                 bool hit = false;
00983                 sint16 attackdex = attacker->getAttackingDex();
00984                 sint16 defenddex = getDefendingDex();
00985                 if (attackdex < 0) attackdex = 0;
00986                 if (defenddex <= 0) defenddex = 1;
00987 
00988                 if ((getActorFlags() & ACT_STUNNED) ||
00989                         (rand() % (attackdex + 3) > rand() % defenddex))
00990                 {
00991                         hit = true;
00992                 }
00993 
00994                 // TODO: give avatar an extra chance to hit monsters
00995                 //       with defense_type DMG_PIERCE
00996 
00997                 if (hit && other == 1) {
00998                         MainActor* av = getMainActor();
00999                         if (attackdex > defenddex)
01000                                 av->accumulateDex(2*(attackdex-defenddex));
01001                         else
01002                                 av->accumulateDex(2);
01003                 }
01004 
01005                 if (!hit) {
01006                         damage = 0;
01007                 }
01008         }
01009 
01010         return damage;
01011 }
01012 
01013 CombatProcess* Actor::getCombatProcess()
01014 {
01015         Process* p = Kernel::get_instance()->findProcess(objid, 0xF2); // CONSTANT!
01016         if (!p) return 0;
01017         CombatProcess* cp = p_dynamic_cast<CombatProcess*>(p);
01018         assert(cp);
01019 
01020         return cp;
01021 }
01022 
01023 void Actor::setInCombat()
01024 {
01025         if ((actorflags &