00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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);
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
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
00150 if (ti.chance < 0.999 &&
00151 (static_cast<double>(std::rand()) / RAND_MAX) > ti.chance)
00152 {
00153 continue;
00154 }
00155
00156
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
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
00182 item = ItemFactory::createItem(s,
00183 0,
00184 count,
00185 Item::FLG_DISPOSABLE,
00186 0,
00187 0,
00188 0, true);
00189 item->moveToContainer(this);
00190 item->randomGumpLocation();
00191 break;
00192 }
00193 } else if (ti.special == "sorcfocus") {
00194
00195 int shape = 397;
00196 int frame;
00197 uint16 quality;
00198
00199 if (std::rand() % 10 < 8)
00200 {
00201
00202 if (std::rand() % 10 < 4) {
00203
00204 frame = 0;
00205 quality = 3 + (std::rand() % 4) +
00206 ((1 + (std::rand()%4))<<8);
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
00222 if (std::rand() % 10 < 2) {
00223
00224 frame = 3;
00225 quality = 3 + (std::rand() % 4) +
00226 ((1 + (std::rand()%7))<<8);
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
00242 if (std::rand() % 10 < 5) {
00243
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
00251
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
00269 if (std::rand() % 10 < 2) {
00270
00271 frame = 9;
00272 quality = 1 + (std::rand() % 2) +
00273 ((10 + (std::rand()%2))<<8);
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
00294
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
00306 item = ItemFactory::createItem(shape,
00307 0,
00308 count,
00309 Item::FLG_DISPOSABLE,
00310 0,
00311 0,
00312 0, true);
00313 item->moveToContainer(this);
00314 item->randomGumpLocation();
00315 item->callUsecodeEvent_combine();
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
00326 for (int i = 0; i < count; ++i) {
00327
00328 int n = std::rand() % ti.shapes.size();
00329 uint32 shape = ti.shapes[n];
00330
00331
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
00347 item = ItemFactory::createItem(shape,
00348 frame,
00349 qual,
00350 Item::FLG_DISPOSABLE,
00351 0,
00352 0,
00353 0, true);
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);
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
00378 if (equiptype == ShapeInfo::SE_NONE && !backpack) return false;
00379
00380
00381
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
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)))
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
00427 setMapNum(newmapnum);
00428
00429
00430 moveToEtherealVoid();
00431
00432
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
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
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);
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:
00544 Kernel::get_instance()->addProcess(new LoiterProcess(this));
00545 return Kernel::get_instance()->addProcess(new DelayProcess(1));
00546 break;
00547 case 1:
00548 setInCombat();
00549 return 0;
00550 case 2:
00551
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;
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
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
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
00668
00669 if (getActorFlags() & ACT_WITHSTANDDEATH) {
00670
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
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
00690 doAnim(Animation::fallBackwards, 8);
00691
00692
00693 return;
00694 }
00695
00696
00697 fallingprocid = killAllButFallAnims(false);
00698 }
00699
00700
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);
00714 else
00715 sfx = 20 + (std::rand() % 3);
00716 AudioProcess* audioproc = AudioProcess::get_instance();
00717 if (audioproc) audioproc->playSFX(sfx, 0x60, objid, 0);
00718 return;
00719 }
00720
00721
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
00736 }
00737 }
00738
00739 if (damage && !fallingprocid) {
00740 ProcId anim1pid = doAnim(Animation::stumbleBackwards, dir);
00741 ProcId anim2pid;
00742 if (isInCombat())
00743
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);
00766 #endif
00767
00768 if (!animprocid)
00769 animprocid = doAnim(Animation::die, getDir());
00770
00771
00772 MainActor* avatar = getMainActor();
00773
00774 if (getEnemyAlignment() & avatar->getAlignment()) {
00775 if (avatar->isInCombat()) {
00776
00777 MusicProcess::get_instance()->playCombatMusic(109);
00778
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
00793
00794 pout << "Actor::die: scheduling resurrection" << std::endl;
00795
00796 int timeout = ((std::rand() % 25) + 5) * 30;
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
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,
00827 Item::FLG_FAST_ONLY,
00828 0,
00829 0,
00830 0, true
00831 );
00832 piece->move(x - 128 + 32*(std::rand()%6),
00833 y - 128 + 32*(std::rand()%6),
00834 z + std::rand()%8 );
00835 piece->hurl(-25 + (std::rand()%50),
00836 -25 + (std::rand()%50),
00837 10 + (std::rand()%10),
00838 4);
00839 }
00840 }
00841
00842 return animprocid;
00843 }
00844
00845 void Actor::killAllButCombatProcesses()
00846 {
00847
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
00874 kernel->killProcessesNotOfType(objid, 0xF0, true);
00875 } else {
00876
00877 killAllButCombatProcesses();
00878 }
00879
00880
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
00913 damage_type &= ~(defense_type & ~(WeaponInfo::DMG_MAGIC |
00914 WeaponInfo::DMG_UNDEAD |
00915 WeaponInfo::DMG_PIERCE));
00916
00917
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
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;
00933 }
00934 }
00935
00936 if ((damage_type & WeaponInfo::DMG_UNDEAD) &&
00937 (defense_type & WeaponInfo::DMG_UNDEAD))
00938 {
00939 damage *= 2;
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;
00948 }
00949 } else {
00950 damage = 0;
00951 }
00952
00953
00954 if (damage && !(damage_type & WeaponInfo::DMG_PIERCE) && !slayer)
00955 {
00956
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;
00967
00968 if (getActorFlags() & ACT_STUNNED)
00969 ACmod /= 2;
00970
00971 if (ACmod > 100) ACmod = 100;
00972
00973
00974 damage = ((100 - ACmod) * damage) / 100;
00975
00976 if (damage < 0) damage = 0;
00977 }
00978
00979
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
00995
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);
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 &