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 "AnimationTracker.h"
00021
00022 #include "GameData.h"
00023 #include "Actor.h"
00024 #include "World.h"
00025 #include "CurrentMap.h"
00026 #include "MainShapeArchive.h"
00027 #include "AnimAction.h"
00028 #include "Direction.h"
00029 #include "ShapeInfo.h"
00030 #include "UCList.h"
00031 #include "LoopScript.h"
00032 #include "getObject.h"
00033
00034 #include "IDataSource.h"
00035 #include "ODataSource.h"
00036 #include "CoreApp.h"
00037
00038
00039
00040 #ifdef WATCHACTOR
00041 static const int watchactor = WATCHACTOR;
00042 #endif
00043
00044 AnimationTracker::AnimationTracker()
00045 {
00046
00047 }
00048
00049 AnimationTracker::~AnimationTracker()
00050 {
00051
00052 }
00053
00054 bool AnimationTracker::init(Actor* actor_, Animation::Sequence action_,
00055 uint32 dir_, PathfindingState* state_)
00056 {
00057 assert(actor_);
00058 actor = actor_->getObjId();
00059 uint32 shape = actor_->getShape();
00060 animaction = GameData::get_instance()->getMainShapes()->
00061 getAnim(shape, action_);
00062 if (!animaction) return false;
00063
00064 dir = dir_;
00065
00066 if (state_ == 0) {
00067 animaction->getAnimRange(actor_, dir, startframe, endframe);
00068 actor_->getLocation(x, y, z);
00069 flipped = (actor_->getFlags() & Item::FLG_FLIPPED) != 0;
00070 firststep = (actor_->getActorFlags() & Actor::ACT_FIRSTSTEP) != 0;
00071 } else {
00072 animaction->getAnimRange(state_->lastanim, state_->direction,
00073 state_->firststep, dir, startframe, endframe);
00074 flipped = state_->flipped;
00075 firststep = state_->firststep;
00076 x = state_->x;
00077 y = state_->y;
00078 z = state_->z;
00079 }
00080 startx = x;
00081 starty = y;
00082 startz = z;
00083
00084 #ifdef WATCHACTOR
00085 if (actor_ && actor_->getObjId() == watchactor) {
00086 pout << "AnimationTracker: playing " << startframe << "-" << endframe
00087 << " (animaction flags: " << std::hex << animaction->flags
00088 << std::dec << ")" << std::endl;
00089
00090 }
00091 #endif
00092
00093 firstframe = true;
00094
00095 done = false;
00096 blocked = false;
00097 unsupported = false;
00098 hitobject = 0;
00099 mode = NormalMode;
00100
00101 return true;
00102 }
00103
00104 unsigned int AnimationTracker::getNextFrame(unsigned int frame)
00105 {
00106 frame++;
00107
00108 if (frame == endframe)
00109 return endframe;
00110
00111
00112 if (frame >= animaction->size) {
00113 if (animaction->flags & (AnimAction::AAF_LOOPING |
00114 AnimAction::AAF_LOOPING2)) {
00115
00116 frame = 1;
00117 } else {
00118 frame = 0;
00119 }
00120 }
00121
00122 return frame;
00123 }
00124
00125 bool AnimationTracker::stepFrom(sint32 x_, sint32 y_, sint32 z_)
00126 {
00127 x = x_;
00128 y = y_;
00129 z = z_;
00130
00131 return step();
00132 }
00133
00134 void AnimationTracker::evaluateMaxAnimTravel(sint32& max_endx, sint32& max_endy, uint32 dir)
00135 {
00136 max_endx = x;
00137 max_endy = y;
00138
00139 if (done) return;
00140
00141 Actor* a = getActor(actor);
00142 assert(a);
00143
00144 unsigned int testframe;
00145 if (firstframe)
00146 testframe = startframe;
00147 else
00148 testframe = getNextFrame(currentframe);
00149
00150 for(;;)
00151 {
00152 AnimFrame& f = animaction->frames[dir][testframe];
00153
00154 sint32 dx = 4 * x_fact[dir] * f.deltadir;
00155 sint32 dy = 4 * y_fact[dir] * f.deltadir;
00156 max_endx += dx;
00157 max_endy += dy;
00158 testframe = getNextFrame(testframe);
00159 if(testframe == endframe)
00160 return;
00161 }
00162 }
00163
00164 bool AnimationTracker::step()
00165 {
00166 if (done) return false;
00167
00168 Actor* a = getActor(actor);
00169 assert(a);
00170
00171 if (firstframe)
00172 currentframe = startframe;
00173 else
00174 currentframe = getNextFrame(currentframe);
00175
00176 if (currentframe == endframe) {
00177 done = true;
00178
00179
00180 if (animaction->flags & AnimAction::AAF_TWOSTEP)
00181 firststep = !firststep;
00182 else
00183 firststep = true;
00184
00185 return false;
00186 }
00187
00188 prevx = x;
00189 prevy = y;
00190 prevz = z;
00191
00192
00193 unsupported = false;
00194 blocked = false;
00195
00196
00197 firstframe = false;
00198
00199 AnimFrame& f = animaction->frames[dir][currentframe];
00200
00201 shapeframe = f.frame;
00202 flipped = f.is_flipped();
00203
00204
00205 sint32 dx = 4 * x_fact[dir] * f.deltadir;
00206 sint32 dy = 4 * y_fact[dir] * f.deltadir;
00207 sint32 dz = f.deltaz;
00208
00209 if (mode == TargetMode && !(f.flags & AnimFrame::AFF_ONGROUND))
00210 {
00211 dx += target_dx;
00212 dy += target_dy;
00213 }
00214
00215
00216 bool actorflipped = (a->getFlags() & Item::FLG_FLIPPED) != 0;
00217 sint32 xd, yd, zd;
00218 a->getFootpadWorld(xd, yd, zd);
00219 if (actorflipped != flipped) {
00220 sint32 t = xd;
00221 xd = yd;
00222 yd = t;
00223 }
00224 CurrentMap* cm = World::get_instance()->getCurrentMap();
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 sint32 tx,ty,tz;
00253 tx = x+dx;
00254 ty = y+dy;
00255 tz = z+dz;
00256
00257 Item* support;
00258 bool targetok = cm->isValidPosition(tx,ty,tz,
00259 startx,starty,startz,
00260 xd,yd,zd,
00261 a->getShapeInfo()->flags,
00262 actor, &support, 0);
00263
00264 if (GAME_IS_U8 && targetok && support)
00265 {
00266
00267 uint32 supportshape = support->getShape();
00268 if(supportshape >= 675 && supportshape <= 681)
00269 {
00270
00271
00272
00273
00274 int descentdelta = 0;
00275 if(supportshape == 675)
00276 descentdelta = -20;
00277 else if(supportshape == 676)
00278 descentdelta = 12;
00279 else if(supportshape == 681)
00280 descentdelta = -20;
00281
00282 if(descentdelta)
00283 {
00284 if(dy == 0 && dx != 0 && !(support->getFlags() & Item::FLG_FLIPPED))
00285 {
00286
00287
00288
00289
00290 ty += descentdelta * dx / 60;
00291 }
00292 else if(dx == 0 && dy != 0 && (support->getFlags() & Item::FLG_FLIPPED))
00293 {
00294
00295 tx += descentdelta * dy / 60;
00296 }
00297 }
00298 }
00299 }
00300
00301 if (!targetok || ((f.flags & AnimFrame::AFF_ONGROUND) && !support)) {
00302
00303
00304 if (actor == 1 && (f.flags & AnimFrame::AFF_ONGROUND)) {
00305 targetok = cm->scanForValidPosition(tx,ty,tz, a, dir,
00306 true, tx,ty,tz);
00307
00308 if (!targetok) {
00309 blocked = true;
00310 return false;
00311 } else {
00312 #ifdef WATCHACTOR
00313 if (a->getObjId() == watchactor) {
00314 pout << "AnimationTracker: adjusted step: "
00315 << tx-(x+dx) << "," << ty-(y+dy) << "," << tz-(z+dz)
00316 << std::endl;
00317 }
00318 #endif
00319 }
00320 } else {
00321 if (!targetok) {
00322 blocked = true;
00323 return false;
00324 }
00325 }
00326 }
00327
00328 #ifdef WATCHACTOR
00329 if (a->getObjId() == watchactor) {
00330 pout << "AnimationTracker: step (" << tx-x << "," << ty-y
00331 << "," << tz-z << ")" << std::endl;
00332 }
00333 #endif
00334
00335 x = tx;
00336 y = ty;
00337 z = tz;
00338
00339
00340
00341 if ((animaction->flags & AnimAction::AAF_ATTACK) &&
00342 (hitobject == 0) && f.attack_range() > 0)
00343 {
00344 checkWeaponHit();
00345 }
00346
00347 if (f.flags & AnimFrame::AFF_ONGROUND) {
00348
00349
00350 cm->isValidPosition(tx,ty,tz,
00351 startx,starty,startz,
00352 xd,yd,zd,
00353 a->getShapeInfo()->flags,
00354 actor, &support, 0);
00355
00356
00357 if (!support) {
00358 unsupported = true;
00359 return false;
00360 } else {
00361 #if 0
00362
00363
00364
00365 Item* supportitem = getItem(support);
00366 assert(supportitem);
00367 if (!supportitem->getShapeInfo()->is_land()) {
00368
00369
00370 unsupported = true;
00371 return false;
00372 }
00373 #endif
00374 }
00375 }
00376
00377 return true;
00378 }
00379
00380 AnimFrame* AnimationTracker::getAnimFrame()
00381 {
00382 return &animaction->frames[dir][currentframe];
00383 }
00384
00385 void AnimationTracker::setTargetedMode(sint32 x_, sint32 y_, sint32 z_)
00386 {
00387 unsigned int i;
00388 int totaldir = 0;
00389 int offGround = 0;
00390 sint32 end_dx, end_dy;
00391
00392 for (i=startframe; i != endframe; i = getNextFrame(i))
00393 {
00394 AnimFrame& f = animaction->frames[dir][i];
00395 totaldir += f.deltadir;
00396 if (!(f.flags & AnimFrame::AFF_ONGROUND))
00397 ++offGround;
00398 }
00399
00400 end_dx = 4 * x_fact[dir] * totaldir;
00401 end_dy = 4 * y_fact[dir] * totaldir;
00402
00403 if (offGround)
00404 {
00405 mode = TargetMode;
00406 target_dx = (x_ - x - end_dx) / offGround;
00407 target_dy = (y_ - y - end_dy) / offGround;
00408 }
00409
00410 }
00411
00412 void AnimationTracker::checkWeaponHit()
00413 {
00414 int range = animaction->frames[dir][currentframe].attack_range();
00415
00416 Actor *a = getActor(actor);
00417 assert(a);
00418
00419
00420 Pentagram::Box abox = a->getWorldBox();
00421 abox.MoveAbs(x,y,z);
00422 abox.MoveRel(x_fact[dir]*32*range,y_fact[dir]*32*range,0);
00423
00424 #ifdef WATCHACTOR
00425 if (a->getObjId() == watchactor) {
00426 pout << "AnimationTracker: Checking hit, range " << range << ", box "
00427 << abox.x << "," << abox.y << "," << abox.z << "," << abox.xd
00428 << "," << abox.yd << "," << abox.zd << ": ";
00429 }
00430 #endif
00431
00432 CurrentMap* cm = World::get_instance()->getCurrentMap();
00433
00434 UCList itemlist(2);
00435 LOOPSCRIPT(script, LS_TOKEN_END);
00436
00437 cm->areaSearch(&itemlist, script, sizeof(script), 0, 320, false, x, y);
00438
00439 ObjId hit = 0;
00440 for (unsigned int i = 0; i < itemlist.getSize(); ++i) {
00441 ObjId itemid = itemlist.getuint16(i);
00442 if (itemid == actor) continue;
00443
00444 Actor* item = getActor(itemid);
00445 if (!item) continue;
00446
00447 Pentagram::Box ibox = item->getWorldBox();
00448
00449 if (abox.Overlaps(ibox))
00450 {
00451 hit = itemid;
00452 #ifdef WATCHACTOR
00453 if (a->getObjId() == watchactor) {
00454 pout << "hit: ";
00455 item->dumpInfo();
00456 }
00457 #endif
00458 break;
00459 }
00460 }
00461
00462 #ifdef WATCHACTOR
00463 if (a->getObjId() == watchactor && !hit) {
00464 pout << "nothing" << std::endl;
00465 }
00466 #endif
00467
00468 hitobject = hit;
00469 }
00470
00471 void AnimationTracker::updateState(PathfindingState& state)
00472 {
00473 state.x = x;
00474 state.y = y;
00475 state.z = z;
00476 state.flipped = flipped;
00477 state.firststep = firststep;
00478 }
00479
00480
00481 void AnimationTracker::updateActorFlags()
00482 {
00483 Actor* a = getActor(actor);
00484 assert(a);
00485
00486 if (flipped)
00487 a->setFlag(Item::FLG_FLIPPED);
00488 else
00489 a->clearFlag(Item::FLG_FLIPPED);
00490
00491 if (firststep)
00492 a->setActorFlag(Actor::ACT_FIRSTSTEP);
00493 else
00494 a->clearActorFlag(Actor::ACT_FIRSTSTEP);
00495
00496 if (animaction) {
00497 bool hanging = (animaction->flags & AnimAction::AAF_HANGING) != 0;
00498 if (hanging)
00499 a->setFlag(Item::FLG_HANGING);
00500 else
00501 a->clearFlag(Item::FLG_HANGING);
00502 }
00503
00504 if (currentframe != endframe)
00505 a->animframe = currentframe;
00506 }
00507
00508 void AnimationTracker::getInterpolatedPosition(sint32& x_, sint32& y_,
00509 sint32& z_, int fc)
00510 {
00511 sint32 dx = x - prevx;
00512 sint32 dy = y - prevy;
00513 sint32 dz = z - prevz;
00514
00515 x_ = prevx + (dx*fc)/(animaction->framerepeat+1);
00516 y_ = prevy + (dy*fc)/(animaction->framerepeat+1);
00517 z_ = prevz + (dz*fc)/(animaction->framerepeat+1);
00518 }
00519
00520 void AnimationTracker::getSpeed(sint32& dx, sint32& dy, sint32& dz)
00521 {
00522 dx = x - prevx;
00523 dy = y - prevy;
00524 dz = z - prevz;
00525 }
00526
00527
00528 void AnimationTracker::save(ODataSource* ods)
00529 {
00530 ods->write4(startframe);
00531 ods->write4(endframe);
00532 uint8 ff = firstframe ? 1 : 0;
00533 ods->write1(ff);
00534 ods->write4(currentframe);
00535
00536 ods->write2(actor);
00537 ods->write1(static_cast<uint8>(dir));
00538
00539 if (animaction) {
00540 ods->write4(animaction->shapenum);
00541 ods->write4(animaction->action);
00542 } else {
00543 ods->write4(0);
00544 ods->write4(0);
00545 }
00546
00547 ods->write4(static_cast<uint32>(prevx));
00548 ods->write4(static_cast<uint32>(prevy));
00549 ods->write4(static_cast<uint32>(prevz));
00550 ods->write4(static_cast<uint32>(x));
00551 ods->write4(static_cast<uint32>(y));
00552 ods->write4(static_cast<uint32>(z));
00553
00554 ods->write2(static_cast<uint16>(mode));
00555 if (mode == TargetMode) {
00556 ods->write4(static_cast<uint32>(target_dx));
00557 ods->write4(static_cast<uint32>(target_dy));
00558 }
00559 uint8 fs = firststep ? 1 : 0;
00560 ods->write1(fs);
00561 uint8 fl = flipped ? 1 : 0;
00562 ods->write1(fl);
00563 ods->write4(shapeframe);
00564
00565 uint8 flag = done ? 1 : 0;
00566 ods->write1(flag);
00567 flag = blocked ? 1 : 0;
00568 ods->write1(flag);
00569 flag = unsupported ? 1 : 0;
00570 ods->write1(flag);
00571 ods->write2(hitobject);
00572 }
00573
00574 bool AnimationTracker::load(IDataSource* ids, uint32 version)
00575 {
00576 startframe = ids->read4();
00577 endframe = ids->read4();
00578 firstframe = (ids->read1() != 0);
00579 currentframe = ids->read4();
00580
00581 actor = ids->read2();
00582 dir = ids->read1();
00583
00584 uint32 shapenum = ids->read4();
00585 uint32 action = ids->read4();
00586 if (shapenum == 0) {
00587 animaction = 0;
00588 } else {
00589 animaction = GameData::get_instance()->getMainShapes()->
00590 getAnim(shapenum, action);
00591 assert(animaction);
00592 }
00593
00594 prevx = ids->read4();
00595 prevy = ids->read4();
00596 prevz = ids->read4();
00597 x = ids->read4();
00598 y = ids->read4();
00599 z = ids->read4();
00600
00601 mode = static_cast<Mode>(ids->read2());
00602 if (mode == TargetMode) {
00603 target_dx = ids->read4();
00604 target_dy = ids->read4();
00605 }
00606
00607 firststep = (ids->read1() != 0);
00608 flipped = (ids->read1() != 0);
00609 shapeframe = ids->read4();
00610
00611 done = (ids->read1() != 0);
00612 blocked = (ids->read1() != 0);
00613 unsupported = (ids->read1() != 0);
00614 hitobject = ids->read2();
00615
00616 return true;
00617 }