00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "Item.h"
00022 #include "GUIApp.h"
00023 #include "Usecode.h"
00024 #include "GameData.h"
00025 #include "UCMachine.h"
00026 #include "UCList.h"
00027 #include "World.h"
00028 #include "DelayProcess.h"
00029 #include "Container.h"
00030 #include "Actor.h"
00031 #include "Kernel.h"
00032 #include "getObject.h"
00033 #include "MainShapeArchive.h"
00034 #include "GumpShapeArchive.h"
00035 #include "Shape.h"
00036 #include "ShapeInfo.h"
00037 #include "ItemFactory.h"
00038 #include "CurrentMap.h"
00039 #include "UCStack.h"
00040 #include "Direction.h"
00041 #include "BarkGump.h"
00042 #include "AskGump.h"
00043 #include "GumpNotifyProcess.h"
00044 #include "ActorBarkNotifyProcess.h"
00045 #include "ContainerGump.h"
00046 #include "PaperdollGump.h"
00047 #include "GameMapGump.h"
00048 #include "WorldPoint.h"
00049 #include "GravityProcess.h"
00050 #include "LoopScript.h"
00051 #include "IDataSource.h"
00052 #include "ODataSource.h"
00053 #include "CameraProcess.h"
00054 #include "SpriteProcess.h"
00055 #include "SliderGump.h"
00056 #include "UCProcess.h"
00057 #include "DestroyItemProcess.h"
00058 #include "AudioProcess.h"
00059 #include "GameInfo.h"
00060 #include "MainActor.h"
00061 #include "MissileTracker.h"
00062
00063 #include <cstdlib>
00064
00065
00066 DEFINE_RUNTIME_CLASSTYPE_CODE(Item,Object);
00067
00068 Item::Item()
00069 : shape(0), frame(0), x(0), y(0), z(0),
00070 flags(0), quality(0), npcnum(0), mapnum(0),
00071 extendedflags(0), parent(0),
00072 cachedShape(0), cachedShapeInfo(0), gump(0), gravitypid(0),
00073 last_setup(0)
00074 {
00075
00076 }
00077
00078
00079 Item::~Item()
00080 {
00081
00082 }
00083
00084 void Item::dumpInfo()
00085 {
00086 pout << "Item " << getObjId() << " (class "
00087 << GetClassType().class_name << ", shape "
00088 << getShape() << ", " << getFrame() << ", (";
00089
00090 if (parent) {
00091 sint32 gx, gy;
00092 getGumpLocation(gx, gy);
00093 pout << gx << "," << gy;
00094 } else {
00095 pout << x << "," << y << "," << z;
00096 }
00097
00098 pout << ") q:" << getQuality()
00099 << ", m:" << getMapNum() << ", n:" << getNpcNum()
00100 << ", f:" << std::hex << getFlags() << ", ef:"
00101 << getExtFlags() << ")" << std::dec << std::endl;
00102 }
00103
00104 Container *Item::getParentAsContainer() const
00105 {
00106
00107 if (!parent) return 0;
00108
00109 Container *p = getContainer(parent);
00110
00111 if (!p) {
00112 perr << "Item " << getObjId() << " parent (" << parent << ") is an invalid Container ObjID" << std::endl;
00113 CANT_HAPPEN();
00114 }
00115
00116 return p;
00117 }
00118
00119 Item* Item::getTopItem()
00120 {
00121 Container *parent = getParentAsContainer();
00122
00123 if (!parent) return this;
00124
00125 while (parent->getParentAsContainer()) {
00126 parent = parent->getParentAsContainer();
00127 }
00128
00129 return parent;
00130 }
00131
00132 void Item::setLocation(sint32 X, sint32 Y, sint32 Z)
00133 {
00134 x = X;
00135 y = Y;
00136 z = Z;
00137 }
00138
00139 void Item::move(sint32 X, sint32 Y, sint32 Z)
00140 {
00141 bool no_lerping = false;
00142 CurrentMap * map = World::get_instance()->getCurrentMap();
00143 int mapChunkSize = map->getChunkSize();
00144
00145 if (getObjId() == 1 && Z < 0) {
00146 perr.printf("Warning: moving avatar below Z=0. (%d,%d,%d)\n", X, Y, Z);
00147 }
00148
00149
00150 if (flags & FLG_ETHEREAL) {
00151
00152
00153 World::get_instance()->etherealRemove(objid);
00154 }
00155
00156
00157 if (flags & (FLG_CONTAINED|FLG_EQUIPPED))
00158 {
00159 if (parent) {
00160
00161 if (!(flags & FLG_ETHEREAL)) {
00162 Container *p = getParentAsContainer();
00163 if (p) p->removeItem(this);
00164 }
00165 }
00166 else
00167 perr << "Item " << getObjId() << " FLG_CONTAINED or FLG_EQUIPPED set but item has no parent" << std::endl;
00168
00169
00170 parent = 0;
00171
00172
00173 no_lerping = true;
00174 }
00175
00176
00177 else if ((extendedflags & EXT_INCURMAP) &&
00178 ((x / mapChunkSize != X / mapChunkSize) ||
00179 (y / mapChunkSize != Y / mapChunkSize))) {
00180
00181
00182 map->removeItem(this);
00183 }
00184
00185
00186 flags &= ~(FLG_CONTAINED|FLG_EQUIPPED|FLG_ETHEREAL);
00187
00188
00189 x = X;
00190 y = Y;
00191 z = Z;
00192
00193
00194 if (!(extendedflags & EXT_INCURMAP))
00195 {
00196
00197
00198 if (flags & (FLG_DISPOSABLE|FLG_FAST_ONLY))
00199 map->addItemToEnd(this);
00200 else
00201 map->addItem(this);
00202 }
00203
00204
00205 callUsecodeEvent_justMoved();
00206
00207
00208 bool dest_fast = map->isChunkFast(X/mapChunkSize, Y/mapChunkSize);
00209
00210
00211 if (no_lerping) extendedflags |= EXT_LERP_NOPREV;
00212
00213
00214
00215
00216 if (!dest_fast && (flags & Item::FLG_FASTAREA)) {
00217 extendedflags |= EXT_LERP_NOPREV;
00218 if (extendedflags & EXT_CAMERA)
00219 CameraProcess::GetCameraProcess()->ItemMoved();
00220 else
00221 leaveFastArea();
00222
00223 return;
00224 }
00225
00226 else if (dest_fast && !(flags & Item::FLG_FASTAREA)) {
00227 extendedflags |= EXT_LERP_NOPREV;
00228 enterFastArea();
00229 }
00230
00231
00232
00233 if (extendedflags & EXT_CAMERA)
00234 CameraProcess::GetCameraProcess()->ItemMoved();
00235 }
00236
00237 bool Item::moveToContainer(Container *container, bool checkwghtvol)
00238 {
00239
00240 if (!container) {
00241 perr << "NULL container passed to Item::moveToContainer" << std::endl;
00242 return false;
00243 }
00244
00245
00246 bool ethereal_same = false;
00247 if ( container->getObjId() == parent ) {
00248
00249 if (flags & FLG_ETHEREAL) ethereal_same = true;
00250 else return true;
00251 }
00252
00253
00254 if (!container->CanAddItem(this,checkwghtvol)) return false;
00255
00256
00257 if (flags & FLG_ETHEREAL) {
00258
00259
00260 World::get_instance()->etherealRemove(objid);
00261 }
00262
00263
00264 if (flags & (FLG_CONTAINED|FLG_EQUIPPED))
00265 {
00266 if (parent) {
00267
00268 if (!(flags & FLG_ETHEREAL)) {
00269 Container *p = getParentAsContainer();
00270 if (p) p->removeItem(this);
00271 }
00272 }
00273 else
00274 perr << "Item " << getObjId() << " FLG_CONTAINED or FLG_EQUIPPED set but item has no parent" << std::endl;
00275
00276
00277 parent = 0;
00278 }
00279
00280 else if (extendedflags & EXT_INCURMAP) {
00281
00282
00283 World::get_instance()->getCurrentMap()->removeItem(this);
00284 }
00285
00286
00287 flags &= ~(FLG_CONTAINED|FLG_EQUIPPED|FLG_ETHEREAL);
00288
00289
00290 if (!ethereal_same) x = y = 0;
00291 z = 0;
00292
00293
00294
00295 container->addItem(this, false);
00296
00297
00298 parent = container->getObjId();
00299
00300
00301 flags |= FLG_CONTAINED;
00302
00303
00304 Item *p = this;
00305 while (p->getParentAsContainer())
00306 p = p->getParentAsContainer();
00307
00308 if (p->getObjId() == 1)
00309 setFlagRecursively(FLG_OWNED);
00310
00311
00312 extendedflags |= EXT_LERP_NOPREV;
00313
00314
00315 callUsecodeEvent_justMoved();
00316
00317
00318 bool dest_fast = (container->flags & FLG_GUMP_OPEN)!=0;
00319
00320
00321
00322 if (!dest_fast && (flags & Item::FLG_FASTAREA))
00323 leaveFastArea();
00324
00325 else if (dest_fast && !(flags & Item::FLG_FASTAREA))
00326 enterFastArea();
00327
00328
00329 return true;
00330 }
00331
00332 void Item::moveToEtherealVoid()
00333 {
00334
00335 if (flags & FLG_ETHEREAL) return;
00336
00337
00338 World::get_instance()->etherealPush(objid);
00339
00340
00341 if (flags & (FLG_CONTAINED|FLG_EQUIPPED)) {
00342
00343 if (parent)
00344 {
00345 Container *p = getParentAsContainer();
00346 if (p) p->removeItem(this);
00347 }
00348 else
00349 perr << "Item " << getObjId() << " FLG_CONTAINED or FLG_EQUIPPED set but item has no parent" << std::endl;
00350 }
00351 else if (extendedflags & EXT_INCURMAP) {
00352 World::get_instance()->getCurrentMap()->removeItem(this);
00353 }
00354
00355
00356 flags |= FLG_ETHEREAL;
00357 }
00358
00359 void Item::returnFromEtherealVoid()
00360 {
00361
00362 if (!(flags & FLG_ETHEREAL)) return;
00363
00364
00365
00366 if (flags & (FLG_CONTAINED|FLG_EQUIPPED)) {
00367 Container *p = getParentAsContainer();
00368 if (!p) {
00369 perr << "Item " << getObjId() << " FLG_CONTAINED or FLG_EQUIPPED set but item has no valid parent" << std::endl;
00370 CANT_HAPPEN();
00371 }
00372 moveToContainer(p);
00373 }
00374
00375 else {
00376 move(x,y,z);
00377 }
00378
00379 }
00380
00381 void Item::movedByPlayer()
00382 {
00383
00384 if (flags & FLG_OWNED) return;
00385
00386
00387
00388 Item* avatar = getItem(1);
00389 UCList itemlist(2);
00390 LOOPSCRIPT(script, LS_TOKEN_TRUE);
00391 CurrentMap* currentmap = World::get_instance()->getCurrentMap();
00392 currentmap->areaSearch(&itemlist, script, sizeof(script),
00393 avatar, 640, false);
00394
00395 for (unsigned int i = 0; i < itemlist.getSize(); ++i) {
00396 Actor *actor = getActor(itemlist.getuint16(i));
00397 if (actor && !actor->isDead())
00398 actor->callUsecodeEvent_AvatarStoleSomething(getObjId());
00399 }
00400 }
00401
00402 sint32 Item::getZ() const
00403 {
00404 return z;
00405 }
00406
00407 void Item::getLocationAbsolute(sint32& X, sint32& Y, sint32& Z) const
00408 {
00409 if (parent) {
00410 Item *p = getParentAsContainer();
00411
00412 if (p) {
00413 p->getLocationAbsolute(X,Y,Z);
00414 return;
00415 }
00416 }
00417
00418 X = x;
00419 Y = y;
00420 Z = z;
00421 }
00422
00423 void Item::getGumpLocation(sint32& X, sint32& Y) const
00424 {
00425 if (!parent) return;
00426
00427 X = y & 0xFF;
00428 Y = (y >> 8) & 0xFF;
00429 }
00430
00431 void Item::setGumpLocation(sint32 X, sint32 Y)
00432 {
00433 if (!parent) return;
00434
00435 y = (X & 0xFF) + ((Y & 0xFF) << 8);
00436 }
00437
00438 void Item::randomGumpLocation()
00439 {
00440 if (!parent) return;
00441
00442
00443
00444 y = 0xFFFF;
00445 }
00446
00447 void Item::getCentre(sint32& X, sint32& Y, sint32& Z) const
00448 {
00449
00450 ShapeInfo *shapeinfo = getShapeInfo();
00451 if (flags & FLG_FLIPPED)
00452 {
00453 X = x - shapeinfo->y * 16;
00454 Y = y - shapeinfo->x * 16;
00455 }
00456 else
00457 {
00458 X = x - shapeinfo->x * 16;
00459 Y = y - shapeinfo->y * 16;
00460 }
00461
00462 Z = z + shapeinfo->z * 4;
00463 }
00464
00465 Pentagram::Box Item::getWorldBox() const
00466 {
00467 sint32 xd,yd,zd;
00468 getFootpadWorld(xd,yd,zd);
00469 return Pentagram::Box(x,y,z,xd,yd,zd);
00470 }
00471
00472 bool Item::overlaps(Item& item2) const
00473 {
00474 sint32 x1a,y1a,z1a,x1b,y1b,z1b;
00475 sint32 x2a,y2a,z2a,x2b,y2b,z2b;
00476 getLocation(x1b,y1b,z1a);
00477 item2.getLocation(x2b,y2b,z2a);
00478
00479 sint32 xd,yd,zd;
00480 getFootpadWorld(xd,yd,zd);
00481 x1a = x1b - xd;
00482 y1a = y1b - yd;
00483 z1b = z1a + zd;
00484
00485 item2.getFootpadWorld(xd,yd,zd);
00486 x2a = x2b - xd;
00487 y2a = y2b - yd;
00488 z2b = z2a + zd;
00489
00490 if (x1b <= x2a || x2b <= x1a) return false;
00491 if (y1b <= y2a || y2b <= y1a) return false;
00492 if (z1b <= z2a || z2b <= z1a) return false;
00493 return true;
00494 }
00495
00496 bool Item::overlapsxy(Item& item2) const
00497 {
00498 sint32 x1a,y1a,z1a,x1b,y1b;
00499 sint32 x2a,y2a,z2a,x2b,y2b;
00500 getLocation(x1b,y1b,z1a);
00501 item2.getLocation(x2b,y2b,z2a);
00502
00503 sint32 xd,yd,zd;
00504 getFootpadWorld(xd,yd,zd);
00505 x1a = x1b - xd;
00506 y1a = y1b - yd;
00507
00508 item2.getFootpadWorld(xd,yd,zd);
00509 x2a = x2b - xd;
00510 y2a = y2b - yd;
00511
00512 if (x1b <= x2a || x2b <= x1a) return false;
00513 if (y1b <= y2a || y2b <= y1a) return false;
00514 return true;
00515 }
00516
00517 bool Item::isOn(Item& item2) const
00518 {
00519 sint32 x1a,y1a,z1a,x1b,y1b;
00520 sint32 x2a,y2a,z2a,x2b,y2b,z2b;
00521 getLocation(x1b,y1b,z1a);
00522 item2.getLocation(x2b,y2b,z2a);
00523
00524 sint32 xd,yd,zd;
00525 getFootpadWorld(xd,yd,zd);
00526 x1a = x1b - xd;
00527 y1a = y1b - yd;
00528
00529 item2.getFootpadWorld(xd,yd,zd);
00530 x2a = x2b - xd;
00531 y2a = y2b - yd;
00532 z2b = z2a + zd;
00533
00534 if (x1b <= x2a || x2b <= x1a) return false;
00535 if (y1b <= y2a || y2b <= y1a) return false;
00536 if (z2b == z1a) return true;
00537 return false;
00538 }
00539
00540 bool Item::canExistAt(sint32 x, sint32 y, sint32 z, bool needsupport) const
00541 {
00542 CurrentMap* cm = World::get_instance()->getCurrentMap();
00543 Item* support;
00544 bool valid = cm->isValidPosition(x, y, z, getShape(), getObjId(),
00545 &support, 0);
00546 return valid && (!needsupport || support);
00547 }
00548
00549 int Item::getDirToItemCentre(Item& item2) const
00550 {
00551 sint32 ix,iy,iz;
00552 getCentre(ix,iy,iz);
00553
00554 sint32 i2x,i2y,i2z;
00555 item2.getCentre(i2x,i2y,i2z);
00556
00557 return Get_WorldDirection(i2y - iy, i2x - ix);
00558 }
00559
00560 int Item::getRange(Item& item2, bool checkz) const
00561 {
00562 sint32 thisX, thisY, thisZ;
00563 sint32 otherX, otherY, otherZ;
00564 sint32 thisXd, thisYd, thisZd;
00565 sint32 otherXd, otherYd, otherZd;
00566 sint32 thisXmin, thisYmin, thisZmax;
00567 sint32 otherXmin, otherYmin, otherZmax;
00568
00569 getLocationAbsolute(thisX, thisY, thisZ);
00570 item2.getLocationAbsolute(otherX, otherY, otherZ);
00571 getFootpadWorld(thisXd, thisYd, thisZd);
00572 item2.getFootpadWorld(otherXd, otherYd, otherZd);
00573
00574 thisXmin = thisX - thisXd;
00575 thisYmin = thisY - thisYd;
00576 thisZmax = thisZ + thisZd;
00577
00578 otherXmin = otherX - otherXd;
00579 otherYmin = otherY - otherYd;
00580 otherZmax = otherZ + otherZd;
00581
00582 sint32 range = 0;
00583
00584 if (thisXmin - otherX > range)
00585 range = thisYmin - otherY;
00586 if (otherXmin - thisX > range)
00587 range = thisXmin - otherX;
00588 if (thisYmin - otherY > range)
00589 range = otherXmin - thisX;
00590 if (otherYmin - thisY > range)
00591 range = otherYmin - thisY;
00592 if (checkz && thisZ - otherZmax > range)
00593 range = thisZ - otherZmax;
00594 if (checkz && otherZ - thisZmax > range)
00595 range = otherZ - thisZmax;
00596
00597 return range;
00598 }
00599
00600 ShapeInfo* Item::getShapeInfoFromGameInstance() const
00601 {
00602 return GameData::get_instance()->getMainShapes()->getShapeInfo(shape);
00603 }
00604
00605 Shape* Item::getShapeObject() const
00606 {
00607 if (!cachedShape) cachedShape = GameData::get_instance()->getMainShapes()->getShape(shape);
00608 return cachedShape;
00609 }
00610
00611 uint16 Item::getFamily()
00612 {
00613 return static_cast<uint16>(getShapeInfo()->family);
00614 }
00615
00616 uint32 Item::getWeight()
00617 {
00618 uint32 weight = getShapeInfo()->weight;
00619
00620 switch (getShapeInfo()->family) {
00621 case ShapeInfo::SF_QUANTITY:
00622 return ((getQuality()*weight)+9)/10;
00623 case ShapeInfo::SF_REAGENT:
00624 return getQuality()*weight;
00625 default:
00626 return weight*10;
00627 }
00628 }
00629
00630 uint32 Item::getTotalWeight()
00631 {
00632 return getWeight();
00633 }
00634
00635 uint32 Item::getVolume()
00636 {
00637
00638 if (getFlags() & FLG_INVISIBLE) return 0;
00639
00640
00641 uint32 volume = getShapeInfo()->volume;
00642
00643 switch (getShapeInfo()->family) {
00644 case ShapeInfo::SF_QUANTITY:
00645 return ((getQuality()*volume)+99)/100;
00646 case ShapeInfo::SF_REAGENT:
00647 return ((getQuality()*volume)+9)/10;
00648 case ShapeInfo::SF_CONTAINER:
00649 return (volume == 0) ? 1 : volume;
00650 default:
00651 return volume;
00652 }
00653 }
00654
00655 bool Item::checkLoopScript(const uint8* script, uint32 scriptsize)
00656 {
00657
00658 DynamicUCStack stack(0x40);
00659
00660 unsigned int i = 0;
00661
00662 uint16 ui16a, ui16b;
00663
00664 stack.push2(1);
00665
00666 while (i < scriptsize) {
00667 switch(script[i]) {
00668 case LS_TOKEN_FALSE:
00669 stack.push2(0); break;
00670
00671 case LS_TOKEN_TRUE:
00672 stack.push2(1); break;
00673
00674 case LS_TOKEN_END:
00675 ui16a = stack.pop2();
00676 return (ui16a != 0);
00677
00678 case LS_TOKEN_INT:
00680 ui16a = script[i+1] + (script[i+2]<<8);
00681 stack.push2(ui16a);
00682 i += 2;
00683 break;
00684
00685 case LS_TOKEN_AND:
00686 ui16a = stack.pop2();
00687 ui16b = stack.pop2();
00688 if (ui16a != 0 && ui16b != 0)
00689 stack.push2(1);
00690 else
00691 stack.push2(0);
00692 break;
00693
00694 case LS_TOKEN_OR:
00695 ui16a = stack.pop2();
00696 ui16b = stack.pop2();
00697 if (ui16a != 0 || ui16b != 0)
00698 stack.push2(1);
00699 else
00700 stack.push2(0);
00701 break;
00702
00703 case LS_TOKEN_NOT:
00704 ui16a = stack.pop2();
00705 if (ui16a != 0)
00706 stack.push2(0);
00707 else
00708 stack.push2(1);
00709 break;
00710
00711 case LS_TOKEN_STATUS:
00712 stack.push2(getFlags());
00713 break;
00714
00715 case LS_TOKEN_Q:
00716 stack.push2(getQuality());
00717 break;
00718
00719 case LS_TOKEN_NPCNUM:
00720 stack.push2(getNpcNum());
00721 break;
00722
00723 case LS_TOKEN_EQUAL:
00724 ui16a = stack.pop2();
00725 ui16b = stack.pop2();
00726 if (ui16a == ui16b)
00727 stack.push2(1);
00728 else
00729 stack.push2(0);
00730 break;
00731
00732 case LS_TOKEN_GREATER:
00733 ui16a = stack.pop2();
00734 ui16b = stack.pop2();
00735 if (ui16b > ui16a)
00736 stack.push2(1);
00737 else
00738 stack.push2(0);
00739 break;
00740
00741 case LS_TOKEN_LESS:
00742 ui16a = stack.pop2();
00743 ui16b = stack.pop2();
00744 if (ui16b < ui16a)
00745 stack.push2(1);
00746 else
00747 stack.push2(0);
00748 break;
00749
00750 case LS_TOKEN_GEQUAL:
00751 ui16a = stack.pop2();
00752 ui16b = stack.pop2();
00753 if (ui16b >= ui16a)
00754 stack.push2(1);
00755 else
00756 stack.push2(0);
00757 break;
00758
00759 case LS_TOKEN_LEQUAL:
00760 ui16a = stack.pop2();
00761 ui16b = stack.pop2();
00762 if (ui16b <= ui16a)
00763 stack.push2(1);
00764 else
00765 stack.push2(0);
00766 break;
00767
00768 case LS_TOKEN_FAMILY:
00769 stack.push2(getFamily());
00770 break;
00771
00772 case LS_TOKEN_SHAPE:
00773 stack.push2(static_cast<uint16>(getShape()));
00774 break;
00775
00776 case 'A': case 'B': case 'C': case 'D': case 'E':
00777 case 'F': case 'G': case 'H': case 'I': case 'J':
00778 case 'K': case 'L': case 'M': case 'N': case 'O':
00779 case 'P': case 'Q': case 'R': case 'S': case 'T':
00780 case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
00781 {
00782 bool match = false;
00783 int count = script[i] - '@';
00784 for (int j = 0; j < count; j++) {
00786 if (getShape() == static_cast<uint32>(script[i+1] + (script[i+2]<<8)))
00787 match = true;
00788 i += 2;
00789 }
00790 if (match)
00791 stack.push2(1);
00792 else
00793 stack.push2(0);
00794 }
00795 break;
00796
00797 case LS_TOKEN_FRAME:
00798 stack.push2(static_cast<uint16>(getFrame()));
00799 break;
00800
00801 case 'a': case 'b': case 'c': case 'd': case 'e':
00802 case 'f': case 'g': case 'h': case 'i': case 'j':
00803 case 'k': case 'l': case 'm': case 'n': case 'o':
00804 case 'p': case 'q': case 'r': case 's': case 't':
00805 case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
00806 {
00807 bool match = false;
00808 int count = script[i] - '`';
00809 for (int j = 0; j < count; j++) {
00811 if (getFrame() == static_cast<uint32>(script[i+1] + (script[i+2]<<8)))
00812 match = true;
00813 i += 2;
00814 }
00815 if (match)
00816 stack.push2(1);
00817 else
00818 stack.push2(0);
00819 }
00820 break;
00821
00822 default:
00823 perr.printf("Unknown loopscript opcode %02X\n", script[i]);
00824 }
00825
00826 i++;
00827 }
00828 perr.printf("Didn't encounter $ in loopscript\n");
00829 return false;
00830 }
00831
00832
00833 sint32 Item::collideMove(sint32 dx, sint32 dy, sint32 dz, bool teleport, bool force, ObjId* hititem)
00834 {
00835 GUIApp *guiapp = GUIApp::get_instance();
00836 World *world = World::get_instance();
00837 CurrentMap *map = world->getCurrentMap();
00838
00839 if (hititem) *hititem = 0;
00840
00841 sint32 end[3] = { dx, dy, dz };
00842
00843 sint32 start[3];
00844 if (parent)
00845 {
00846
00847 start[0] = end[0];
00848 start[1] = end[1];
00849 start[2] = end[2];
00850 }
00851 else
00852 {
00853
00854 getLocation(start[0], start[1], start[2]);
00855 }
00856
00857 sint32 dims[3];
00858 getFootpadWorld(dims[0], dims[1], dims[2]);
00859
00860
00861 std::list<CurrentMap::SweepItem> collisions;
00862 std::list<CurrentMap::SweepItem>::iterator it;
00863 map->sweepTest(start, end, dims, getShapeInfo()->flags, objid,
00864 false, &collisions);
00865
00866
00867
00868
00869
00870 int deltax = abs(start[0] - end[0])/4;
00871 int deltay = abs(start[1] - end[1])/4;
00872 int deltaz = abs(start[2] - end[2]);
00873 int maxdirdelta = deltay;
00874 if (deltay > maxdirdelta) maxdirdelta = deltay;
00875 if (deltaz > maxdirdelta) maxdirdelta = deltaz;
00876 int hitforce = (deltax+deltay+deltaz+maxdirdelta)/2;
00877
00878
00879 if (teleport || parent)
00880 {
00881
00882 if (!force)
00883 {
00884 for (it = collisions.begin(); it != collisions.end(); it++)
00885 {
00886
00887 if (it->end_time == 0x4000 && !it->touching && it->blocking) {
00888 if (hititem) *hititem = it->item;
00889 return 0;
00890 }
00891 }
00892 }
00893
00894
00895 bool we_were_released = false;
00896 for (it = collisions.begin(); it != collisions.end(); it++)
00897 {
00898 Item *item = getItem(it->item);
00899
00900
00901 if (!parent && it->hit_time == 0x0000 &&
00902 it->end_time == 0x4000)
00903 {
00904 continue;
00905 }
00906
00907 else if (it->end_time == 0x4000)
00908 {
00909 if (objid == 1 && guiapp->isShowTouchingItems())
00910 item->setExtFlag(Item::EXT_HIGHLIGHT);
00911
00912 item->callUsecodeEvent_gotHit(objid, hitforce);
00913 callUsecodeEvent_hit(item->getObjId(), hitforce);
00914 }
00915
00916 else if (!parent && it->hit_time == 0x0000)
00917 {
00918 if (objid == 1) item->clearExtFlag(Item::EXT_HIGHLIGHT);
00919 we_were_released = true;
00920 item->callUsecodeEvent_release();
00921 }
00922 }
00923
00924
00925 if (we_were_released) callUsecodeEvent_release();
00926
00927
00928 move(end[0], end[1], end[2]);
00929
00930
00931 return 0x4000;
00932 }
00933 else
00934 {
00935 sint32 hit = 0x4000;
00936
00937
00938
00939
00940 if (!force)
00941 {
00942 for (it = collisions.begin(); it != collisions.end(); it++)
00943 {
00944 if (it->blocking && !it->touching) {
00945 if (hititem) *hititem = it->item;
00946 hit = it->hit_time;
00947 break;
00948 }
00949 }
00950 if (hit < 0) hit = 0;
00951
00952 if (hit != 0x4000)
00953 {
00954 #if 0
00955 pout << " Hit time: " << hit << std::endl;
00956 pout << " Start: " << start[0] << ", "<< start[1] << ", " << start[2] << std::endl;
00957 pout << " End: " << end[0] << ", "<< end[1] << ", " << end[2] << std::endl;
00958 #endif
00959 it->GetInterpolatedCoords(end,start,end);
00960 #if 0
00961 pout << "Collision: " << end[0] << ", "<< end[1] << ", " << end[2] << std::endl;
00962 #endif
00963 }
00964 }
00965
00966
00967 bool we_were_released = false;
00968 for (it = collisions.begin(); it != collisions.end(); it++)
00969 {
00970 Item *item = getItem(it->item);
00971 if (!item) continue;
00972
00973
00974 if (it->hit_time > hit) break;
00975
00976 uint16 proc_gothit = 0, proc_rel = 0;
00977
00978
00979
00980 if ((!it->touching || it->touching_floor) && it->hit_time >= 0)
00981 {
00982 if (objid == 1 && guiapp->isShowTouchingItems())
00983 item->setExtFlag(Item::EXT_HIGHLIGHT);
00984
00985 proc_gothit = item->callUsecodeEvent_gotHit(objid, hitforce);
00986 callUsecodeEvent_hit(item->getObjId(), hitforce);
00987 }
00988
00989
00990 if (it->end_time < hit)
00991 {
00992 if (objid == 1) item->clearExtFlag(Item::EXT_HIGHLIGHT);
00993 we_were_released = true;
00994 proc_rel = item->callUsecodeEvent_release();
00995 }
00996
00997
00998 if (proc_rel && proc_gothit)
00999 {
01000 Process *p = Kernel::get_instance()->getProcess(proc_rel);
01001 p->waitFor(proc_gothit);
01002 }
01003 }
01004
01005
01006 if (we_were_released) callUsecodeEvent_release();
01007
01008
01009 move(end[0], end[1], end[2]);
01010
01011 return hit;
01012 }
01013
01014 return 0;
01015 }
01016
01017 unsigned int Item::countNearby(uint32 shape, uint16 range)
01018 {
01019 CurrentMap* currentmap = World::get_instance()->getCurrentMap();
01020 UCList itemlist(2);
01021 LOOPSCRIPT(script, LS_SHAPE_EQUAL(shape));
01022 currentmap->areaSearch(&itemlist, script, sizeof(script),
01023 this, range, false);
01024 return itemlist.getSize();
01025 }
01026
01027