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
01028 uint32 Item::callUsecodeEvent(uint32 event, const uint8* args, int argsize)
01029 {
01030 uint32 class_id = shape;
01031
01032
01033
01034
01035
01036
01037 if (objid < 256 && (extendedflags & EXT_PERMANENT_NPC))
01038 class_id = objid + 1024;
01039
01040
01041
01042 if (objid < 256 && !(extendedflags & EXT_PERMANENT_NPC) &&
01043 !(flags & FLG_FAST_ONLY))
01044 return 0;
01045
01046
01047 if (getFamily() == ShapeInfo::SF_UNKEGG)
01048 class_id = quality + 0x47F;
01049
01050 Usecode* u = GameData::get_instance()->getMainUsecode();
01051 uint32 offset = u->get_class_event(class_id, event);
01052 if (!offset) return 0;
01053
01054 #ifdef DEBUG
01055 if (UCMachine::get_instance()->trace_event()) {
01056 pout.printf("Item: %d calling usecode event %d @ %04X:%04X\n",
01057 objid, event, class_id, offset);
01058 }
01059 #endif
01060
01061
01062 if (GAME_IS_CRUSADER && event != 1) return 0;
01063
01064 return callUsecode(static_cast<uint16>(class_id),
01065 static_cast<uint16>(offset),
01066 args, argsize);
01067 }
01068
01069 uint32 Item::callUsecodeEvent_look()
01070 {
01071 return callUsecodeEvent(0);
01072 }
01073
01074 uint32 Item::callUsecodeEvent_use()
01075 {
01076 return callUsecodeEvent(1);
01077 }
01078
01079 uint32 Item::callUsecodeEvent_anim()
01080 {
01081 return callUsecodeEvent(2);
01082 }
01083
01084 uint32 Item::callUsecodeEvent_cachein()
01085 {
01086 return callUsecodeEvent(4);
01087 }
01088
01089 uint32 Item::callUsecodeEvent_hit(uint16 hitter, sint16 hitforce)
01090 {
01091 DynamicUCStack arg_stack(4);
01092 arg_stack.push2(hitforce);
01093 arg_stack.push2(hitter);
01094 return callUsecodeEvent(5, arg_stack.access(), 4);
01095 }
01096
01097 uint32 Item::callUsecodeEvent_gotHit(uint16 hitter, sint16 hitforce)
01098 {
01099 DynamicUCStack arg_stack(4);
01100 arg_stack.push2(hitforce);
01101 arg_stack.push2(hitter);
01102 return callUsecodeEvent(6, arg_stack.access(), 4);
01103 }
01104
01105 uint32 Item::callUsecodeEvent_hatch()
01106 {
01107 return callUsecodeEvent(7);
01108 }
01109
01110 uint32 Item::callUsecodeEvent_schedule(uint32 time)
01111 {
01112 DynamicUCStack arg_stack(4);
01113 arg_stack.push4(time);
01114 return callUsecodeEvent(8, arg_stack.access(), 4);
01115 }
01116
01117 uint32 Item::callUsecodeEvent_release()
01118 {
01119 return callUsecodeEvent(9);
01120 }
01121
01122 uint32 Item::callUsecodeEvent_combine()
01123 {
01124 return callUsecodeEvent(0xC);
01125 }
01126
01127 uint32 Item::callUsecodeEvent_enterFastArea()
01128 {
01129 return callUsecodeEvent(0xF);
01130 }
01131
01132 uint32 Item::callUsecodeEvent_leaveFastArea()
01133 {
01134 return callUsecodeEvent(0x10);
01135 }
01136
01137 uint32 Item::callUsecodeEvent_cast(uint16 unk)
01138 {
01139 DynamicUCStack arg_stack(2);
01140 arg_stack.push2(unk);
01141 return callUsecodeEvent(0x11, arg_stack.access(), 2);
01142 }
01143
01144 uint32 Item::callUsecodeEvent_justMoved()
01145 {
01146 return callUsecodeEvent(0x12);
01147 }
01148
01149 uint32 Item::callUsecodeEvent_AvatarStoleSomething(uint16 unk)
01150 {
01151 DynamicUCStack arg_stack(2);
01152 arg_stack.push2(unk);
01153 return callUsecodeEvent(0x13, arg_stack.access(), 2);
01154 }
01155
01156 uint32 Item::callUsecodeEvent_guardianBark(sint16 unk)
01157 {
01158 DynamicUCStack arg_stack(2);
01159 arg_stack.push2(unk);
01160 return callUsecodeEvent(0x15, arg_stack.access(), 2);
01161 }
01162
01163 uint32 Item::use()
01164 {
01165 Actor* actor = p_dynamic_cast<Actor*>(this);
01166 if (actor) {
01167 if (actor->isDead()) {
01168
01169 if (getFlags() & FLG_GUMP_OPEN) {
01170 closeGump();
01171 } else {
01172 openGump(12);
01173 }
01174 return 0;
01175 }
01176 }
01177
01178 return callUsecodeEvent_use();
01179 }
01180
01181 void Item::destroy(bool delnow)
01182 {
01183 if (flags & FLG_ETHEREAL) {
01184
01185 World::get_instance()->etherealRemove(objid);
01186 }
01187 else if (parent) {
01188
01190 Container *p = getParentAsContainer();
01191 if (p) p->removeItem(this);
01192 } else if (extendedflags & EXT_INCURMAP) {
01193
01194 World::get_instance()->getCurrentMap()->removeItemFromList(this,x,y);
01195 }
01196
01197 if (extendedflags & Item::EXT_CAMERA)
01198 CameraProcess::SetCameraProcess(0);
01199
01200
01201 if (!delnow) {
01202 Process* dap = new DestroyItemProcess(this);
01203 Kernel::get_instance()->addProcess(dap);
01204 return;
01205 }
01206
01207 clearObjId();
01208 delete this;
01209 }
01210
01211
01212
01213
01214
01215
01216 void Item::setupLerp(sint32 gametick)
01217 {
01218
01219 if (last_setup && gametick == last_setup)
01220 return;
01221
01222
01223 bool no_lerp = false;
01224
01225
01226
01227 if ((last_setup == 0) || (l_next.shape != shape) ||
01228 (extendedflags & EXT_LERP_NOPREV) ||
01229 (gametick-last_setup)>1 || flags & FLG_CONTAINED)
01230 no_lerp = true;
01231
01232
01233 last_setup = gametick;
01234
01235
01236 extendedflags &= ~EXT_LERP_NOPREV;
01237
01238
01239 if ((gametick%3) == (objid%3)) animateItem();
01240
01241
01242 if (!no_lerp) l_prev = l_next;
01243
01244
01245 if (flags & FLG_CONTAINED) {
01246 l_next.x = ix = y & 0xFF;
01247 l_next.y = iy = (y >> 8) & 0xFF;
01248 l_next.z = iz = 0;
01249 }
01250 else {
01251 l_next.x = ix = x;
01252 l_next.y = iy = y;
01253 l_next.z = iz = z;
01254 }
01255 l_next.shape = shape;
01256 l_next.frame = frame;
01257
01258
01259 if (no_lerp) l_prev = l_next;
01260 }
01261
01262
01263 void Item::animateItem()
01264 {
01265 ShapeInfo *info = getShapeInfo();
01266 Shape *shp = getShapeObject();
01267
01268 if (!info->animtype) return;
01269
01270 int anim_data = info->animdata;
01271 bool dirty = false;
01272
01273 if ((static_cast<int>(last_setup)%6) != (objid%6) && info->animtype != 1)
01274 return;
01275
01276 switch(info->animtype) {
01277 case 2:
01278
01279 if (std::rand() & 1) break;
01280
01281 case 1:
01282 case 3:
01283
01284 if (anim_data == 1 && (std::rand() & 1) ) break;
01285 frame ++;
01286 if (anim_data < 2) {
01287 if (shp && frame == shp->frameCount()) frame = 0;
01288 }
01289 else {
01290 unsigned int num = (frame-1) / anim_data;
01291 if (frame == ((num+1)*anim_data)) frame = num*anim_data;
01292 }
01293 dirty = true;
01294 break;
01295
01296 case 4:
01297 if (!(std::rand() % anim_data)) break;
01298 frame ++;
01299 if (shp && frame == shp->frameCount()) frame = 0;
01300 dirty = true;
01301 break;
01302
01303
01304 case 5:
01305 callUsecodeEvent_anim();
01306 dirty = true;
01307 break;
01308
01309 case 6:
01310 if (anim_data < 2) {
01311 if (frame == 0) break;
01312 frame ++;
01313 if (shp && frame == shp->frameCount()) frame = 1;
01314 }
01315 else {
01316 if (!(frame % anim_data)) break;
01317 frame ++;
01318 unsigned int num = (frame-1) / anim_data;
01319 if (frame == ((num+1)*anim_data)) frame = num*anim_data+1;
01320 }
01321 dirty = true;
01322 break;
01323
01324 default:
01325 pout << "type " << info->animtype << " data " << anim_data <<std::endl;
01326 break;
01327 }
01328
01329 }
01330
01331
01332
01333 void Item::enterFastArea()
01334 {
01336 if (shape == 0x2c8) return;
01337
01338
01339 if (!(flags & FLG_FASTAREA)) {
01340
01341 Actor* actor = p_dynamic_cast<Actor*>(this);
01342 if (actor && actor->isDead()) {
01343
01344 } else {
01345 callUsecodeEvent_enterFastArea();
01346 }
01347 }
01348
01349
01350 flags |= FLG_FASTAREA;
01351 }
01352
01353
01354 void Item::leaveFastArea()
01355 {
01356
01357 if ((!(flags & FLG_FAST_ONLY) || getShapeInfo()->is_noisy()) &&
01358 (flags & FLG_FASTAREA))
01359 callUsecodeEvent_leaveFastArea();
01360
01361
01362 if (!parent && (flags & FLG_GUMP_OPEN))
01363 {
01364 Gump *g = GUIApp::get_instance()->getGump(gump);
01365 if (g) g->Close();
01366 }
01367
01368
01369 flags &= ~FLG_FASTAREA;
01370
01371
01372
01373
01374
01375 if ((flags & FLG_FAST_ONLY) && !getParent()) {
01376
01377 Container* c = p_dynamic_cast<Container*>(this);
01378 if (c) c->destroyContents();
01379
01380 destroy();
01381
01382
01383 }
01384
01385 else if (gravitypid)
01386 {
01387 Process *p = Kernel::get_instance()->getProcess(gravitypid);
01388 if (p) {
01389 p->terminateDeferred();
01390 gravitypid = 0;
01391 collideMove(x,y,0,true,false);
01392 }
01393 }
01394 }
01395
01396 uint16 Item::openGump(uint32 gumpshape)
01397 {
01398 if (flags & FLG_GUMP_OPEN) return 0;
01399 assert(gump == 0);
01400 Shape* shape = GameData::get_instance()->getGumps()->getShape(gumpshape);
01401
01402 ContainerGump* cgump;
01403
01404 if (getObjId() != 1) {
01405 cgump = new ContainerGump(shape, 0, objid, Gump::FLAG_ITEM_DEPENDENT |
01406 Gump::FLAG_DRAGGABLE);
01407 } else {
01408 cgump = new PaperdollGump(shape, 0, objid, Gump::FLAG_ITEM_DEPENDENT |
01409 Gump::FLAG_DRAGGABLE);
01410 }
01414 cgump->setItemArea(GameData::get_instance()->
01415 getGumps()->getGumpItemArea(gumpshape));
01416 cgump->InitGump(0);
01417 flags |= FLG_GUMP_OPEN;
01418 gump = cgump->getObjId();
01419
01420 return gump;
01421 }
01422
01423 void Item::closeGump()
01424 {
01425 if (!(flags & FLG_GUMP_OPEN)) return;
01426
01427 Gump* g = GUIApp::get_instance()->getGump(gump);
01428 assert(g);
01429 g->Close();
01430
01431
01432
01433 clearGump();
01434 }
01435
01436
01437 void Item::clearGump()
01438 {
01439 gump = 0;
01440 flags &= ~FLG_GUMP_OPEN;
01441 }
01442
01443 sint32 Item::ascend(int delta)
01444 {
01445
01446
01447 if (delta == 0) return 0x4000;
01448
01449
01450
01451
01452
01453
01454
01455 UCList uclist(2);
01456 LOOPSCRIPT(script, LS_TOKEN_TRUE);
01457 World* world= World::get_instance();
01458 world->getCurrentMap()->surfaceSearch(&uclist, script, sizeof(script),
01459 this, true, false, false);
01460 for (uint32 i = 0; i < uclist.getSize(); i++)
01461 {
01462 Item *item = getItem(uclist.getuint16(i));
01463 if (!item) continue;
01464 if (item->getShapeInfo()->is_fixed()) continue;
01465
01466 item->moveToEtherealVoid();
01467 }
01468
01469
01470 sint32 ix,iy,iz;
01471 getLocation(ix,iy,iz);
01472 int dist = collideMove(ix, iy, iz+delta, false, false);
01473 delta = (delta * dist) / 0x4000;
01474
01475
01476
01477
01478 for (uint32 i = 0; i < uclist.getSize(); i++)
01479 {
01480 Item *item = getItem(uclist.getuint16(i));
01481 if (!item) continue;
01482 if (item->getShapeInfo()->is_fixed()) continue;
01483
01484 item->getLocation(ix, iy, iz);
01485
01486 if (item->canExistAt(ix, iy, iz+delta)) {
01487 item->move(ix, iy, iz+delta);
01488 } else {
01489
01490
01491 item->move(ix, iy, iz);
01492 if (delta < 0) item->fall();
01493 }
01494 }
01495
01496 return dist;
01497 }
01498
01499 GravityProcess* Item::ensureGravityProcess()
01500 {
01501 GravityProcess* p = 0;
01502 if (gravitypid) {
01503 p = p_dynamic_cast<GravityProcess*>(
01504 Kernel::get_instance()->getProcess(gravitypid));
01505 } else {
01506 p = new GravityProcess(this, 0);
01507 Kernel::get_instance()->addProcess(p);
01508 p->init();
01509 }
01510 assert(p);
01511 return p;
01512 }
01513
01514 void Item::fall()
01515 {
01516 if (flags & FLG_HANGING || getShapeInfo()->is_fixed()) {
01517
01518 return;
01519 }
01520
01521 GravityProcess* p = ensureGravityProcess();
01522 p->setGravity(4);
01523 }
01524
01525 void Item::grab()
01526 {
01527
01528
01529 UCList uclist(2);
01530 LOOPSCRIPT(script, LS_TOKEN_TRUE);
01531 World* world= World::get_instance();
01532 world->getCurrentMap()->surfaceSearch(&uclist, script, sizeof(script),
01533 this, true, false, true);
01534
01535 for (uint32 i = 0; i < uclist.getSize(); i++)
01536 {
01537 Item *item = getItem(uclist.getuint16(i));
01538 if (!item) continue;
01539 item->fall();
01540 }
01541
01542 uclist.free();
01543
01544 world->getCurrentMap()->surfaceSearch(&uclist, script, sizeof(script),
01545 this, false, true, false);
01546
01547 for (uint32 i = 0; i < uclist.getSize(); i++)
01548 {
01549 Item *item = getItem(uclist.getuint16(i));
01550 if (!item) continue;
01551 item->callUsecodeEvent_release();
01552 }
01553
01554 }
01555
01556
01557 void Item::hurl(int xs, int ys, int zs, int grav)
01558 {
01559 GravityProcess* p = ensureGravityProcess();
01560 p->setGravity(grav);
01561 p->move(xs,ys,zs);
01562 }
01563
01564
01565 void Item::explode()
01566 {
01567 Process *p = new SpriteProcess(578, 20, 34, 1, 1,
01568 x, y, z);
01569 Kernel::get_instance()->addProcess(p);
01570
01571 int sfx = (std::rand()%2) ? 31 : 158;
01572 AudioProcess* audioproc = AudioProcess::get_instance();
01573 if (audioproc) audioproc->playSFX(sfx, 0x60, 0, 0);
01574
01575 sint32 x,y,z;
01576 getLocation(x,y,z);
01577
01578 destroy();
01579
01580
01581 UCList itemlist(2);
01582 LOOPSCRIPT(script, LS_TOKEN_TRUE);
01583 CurrentMap* currentmap = World::get_instance()->getCurrentMap();
01584 currentmap->areaSearch(&itemlist, script, sizeof(script), 0,
01585 160, false, x, y);
01586
01587 for (unsigned int i = 0; i < itemlist.getSize(); ++i) {
01588 Item *item = getItem(itemlist.getuint16(i));
01589 if (!item) continue;
01590 if (getRange(*item, true) > 160) continue;
01591 sint32 ix,iy,iz;
01592 item->getLocation(ix,iy,iz);
01593 int dir = Get_WorldDirection(ix-x, iy-y);
01594 item->receiveHit(0, dir, 6 + (std::rand()%6),
01595 WeaponInfo::DMG_BLUNT|WeaponInfo::DMG_FIRE);
01596 }
01597 }
01598
01599 uint16 Item::getDamageType()
01600 {
01601 ShapeInfo* si = getShapeInfo();
01602 if (si->weaponinfo) {
01603 return si->weaponinfo->damage_type;
01604 }
01605
01606 return 0;
01607 }
01608
01609 void Item::receiveHit(uint16 other, int dir, int damage, uint16 type)
01610 {
01611
01612 if (callUsecodeEvent_gotHit(other, 0))
01613 return;
01614
01615
01616 if (getShapeInfo()->is_explode()) {
01617 explode();
01618 return;
01619 }
01620
01621
01622 if (getFamily() == ShapeInfo::SF_BREAKABLE) {
01623
01624 destroy();
01625 return;
01626 }
01627
01628 if (getShapeInfo()->is_fixed() || getShapeInfo()->weight == 0) {
01629
01630 return;
01631 }
01632
01633
01634
01635 hurl(-16*x_fact[dir],-16*y_fact[dir],16,4);
01636 }
01637
01638 bool Item::canDrag()
01639 {
01640 ShapeInfo* si = getShapeInfo();
01641 if (si->is_fixed()) return false;
01642 if (si->weight == 0) return false;
01643
01644 Actor* actor = p_dynamic_cast<Actor*>(this);
01645 if (actor) {
01646
01647 if (!actor->isDead()) return false;
01648 }
01649
01650
01651
01652 return true;
01653 }
01654
01655 int Item::getThrowRange()
01656 {
01657 if (!canDrag()) return 0;
01658
01659 Actor* avatar = getMainActor();
01660
01661 int range = 64 - getTotalWeight() + avatar->getStr();
01662 if (range < 1) range = 1;
01663 range = (range * range)/2;
01664
01665 return range;
01666 }
01667
01668 static bool checkLineOfSightCollisions(
01669 const std::list<CurrentMap::SweepItem>& collisions,
01670 bool usingAlternatePos, ObjId item, ObjId other)
01671 {
01672 std::list<CurrentMap::SweepItem>::const_iterator it;
01673 sint32 other_hit_time = 0x4000;
01674 sint32 blocked_time = 0x4000;
01675 for (it = collisions.begin(); it != collisions.end(); it++)
01676 {
01677
01678 if (it->item == item) continue;
01679 if (it->item == other && !usingAlternatePos) {
01680 other_hit_time = it->hit_time;
01681 continue;
01682 }
01683
01684
01685 if (it->touching) continue;
01686
01687
01688 if (it->blocking && it->hit_time < blocked_time) {
01689 blocked_time = it->hit_time;
01690 }
01691 }
01692
01693
01694 return (blocked_time >= other_hit_time);
01695 }
01696
01697 bool Item::canReach(Item* other, int range,
01698 sint32 otherX, sint32 otherY, sint32 otherZ)
01699 {
01700
01701 sint32 thisX, thisY, thisZ;
01702 sint32 thisXd, thisYd, thisZd;
01703 sint32 otherXd, otherYd, otherZd;
01704 sint32 thisXmin, thisYmin;
01705 sint32 otherXmin, otherYmin;
01706
01707 bool usingAlternatePos = (otherX != 0);
01708
01709 getLocationAbsolute(thisX, thisY, thisZ);
01710 other = other->getTopItem();
01711 if (otherX == 0)
01712 other->getLocationAbsolute(otherX, otherY, otherZ);
01713
01714 getFootpadWorld(thisXd, thisYd, thisZd);
01715 other->getFootpadWorld(otherXd, otherYd, otherZd);
01716
01717 thisXmin = thisX - thisXd;
01718 thisYmin = thisY - thisYd;
01719
01720 otherXmin = otherX - otherXd;
01721 otherYmin = otherY - otherYd;
01722
01723
01724 if (thisXmin - otherX > range) return false;
01725 if (otherXmin - thisX > range) return false;
01726 if (thisYmin - otherY > range) return false;
01727 if (otherYmin - thisY > range) return false;
01728
01729
01730
01731 sint32 start[3];
01732 sint32 end[3];
01733 sint32 dims[3] = { 2, 2, 2 };
01734
01735 start[0] = thisX; start[1] = thisY; start[2] = thisZ;
01736 end[0] = otherX; end[1] = otherY; end[2] = otherZ;
01737 if (otherZ > thisZ && otherZ < thisZ + thisZd)
01738 start[2] = end[2];
01739
01740 std::list<CurrentMap::SweepItem> collisions;
01741 std::list<CurrentMap::SweepItem>::iterator it;
01742 World *world = World::get_instance();
01743 CurrentMap *map = world->getCurrentMap();
01744 map->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
01745 objid, false, &collisions);
01746 if (checkLineOfSightCollisions(collisions, usingAlternatePos,
01747 getObjId(), other->getObjId()))
01748 return true;
01749
01750
01751 start[0] = thisX - thisXd/2;
01752 start[1] = thisY - thisYd/2;
01753 start[2] = thisZ;
01754 if (thisZd > 16)
01755 start[2] += thisZd - 8;
01756
01757 end[0] = otherX - otherXd/2;
01758 end[1] = otherY - otherYd/2;
01759 end[2] = otherZ + otherZd/2;
01760
01761 collisions.clear();
01762 map->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
01763 objid, false, &collisions);
01764 if (checkLineOfSightCollisions(collisions, usingAlternatePos,
01765 getObjId(), other->getObjId()))
01766 return true;
01767
01768
01769 end[2] = otherZ + otherZd;
01770
01771 collisions.clear();
01772 map->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
01773 objid, false, &collisions);
01774 return checkLineOfSightCollisions(collisions, usingAlternatePos,
01775 getObjId(), other->getObjId());
01776 }
01777
01778 bool Item::canMergeWith(Item* other)
01779 {
01780
01781 if (other->getObjId() == getObjId()) return false;
01782
01783 if (other->getShape() != getShape()) return false;
01784
01785 int family = getFamily();
01786 if (family == ShapeInfo::SF_QUANTITY) return true;
01787
01788 if (family != ShapeInfo::SF_REAGENT) return false;
01789
01790 uint32 frame1 = getFrame();
01791 uint32 frame2 = other->getFrame();
01792 if (frame1 == frame2) return true;
01793
01794
01795
01796
01797
01798
01799
01800
01801 if (CoreApp::get_instance()->getGameInfo()->type == GameInfo::GAME_U8)
01802 {
01803 if (getShape() != 395) return false;
01804
01805 if (frame1 <= 5 && frame2 <= 5)
01806 return true;
01807 if (frame1 >= 6 && frame1 <= 7 && frame2 >= 6 && frame2 <= 7)
01808 return true;
01809 if (frame1 >= 10 && frame1 <= 12 && frame2 >= 10 && frame2 <= 12)
01810 return true;
01811 if (frame1 >= 14 && frame1 <= 15 && frame2 >= 14 && frame2 <= 15)
01812 return true;
01813 }
01814 return false;
01815 }
01816
01817
01818 void Item::saveData(ODataSource* ods)
01819 {
01820 Object::saveData(ods);
01821 ods->write2(static_cast<uint16>(extendedflags));
01822 ods->write2(flags);
01823 ods->write2(static_cast<uint16>(shape));
01824 ods->write2(static_cast<uint16>(frame));
01825 ods->write2(static_cast<uint16>(x));
01826 ods->write2(static_cast<uint16>(y));
01827 ods->write2(static_cast<uint16>(z));
01828 ods->write2(quality);
01829 ods->write2(npcnum);
01830 ods->write2(mapnum);
01831 if (getObjId() != 0xFFFF) {
01832
01833 ods->write2(gump);
01834 ods->write2(gravitypid);
01835 }
01836 if ((flags & FLG_ETHEREAL) && (flags & (FLG_CONTAINED|FLG_EQUIPPED)))
01837 ods->write2(parent);
01838 }
01839
01840 bool Item::loadData(IDataSource* ids, uint32 version)
01841 {
01842 if (!Object::loadData(ids, version)) return false;
01843
01844 extendedflags = ids->read2();
01845 flags = ids->read2();
01846 shape = ids->read2();
01847 frame = ids->read2();
01848 x = ids->read2();
01849 y = ids->read2();
01850 z = ids->read2();
01851
01852 quality = ids->read2();
01853 npcnum = ids->read2();
01854 mapnum = ids->read2();
01855 if (getObjId() != 0xFFFF) {
01856 gump = ids->read2();
01857 gravitypid = ids->read2();
01858 } else {
01859 gump = gravitypid = 0;
01860 }
01861
01862 if ((flags & FLG_ETHEREAL) && (flags & (FLG_CONTAINED|FLG_EQUIPPED)))
01863 parent = ids->read2();
01864 else
01865 parent = 0;
01866
01868 if (extendedflags & EXT_INCURMAP) {
01869 World::get_instance()->getCurrentMap()->addItem(this);
01870 }
01871
01872 return true;
01873 }
01874
01875
01876 uint32 Item::I_touch(const uint8* args, unsigned int )
01877 {
01878 ARG_NULL32();
01879
01880
01881
01882
01883 return 0;
01884 }
01885
01886 uint32 Item::I_getX(const uint8* args, unsigned int )
01887 {
01888 ARG_ITEM_FROM_PTR(item);
01889 if (!item) return 0;
01890
01891 sint32 x,y,z;
01892 item->getLocationAbsolute(x,y,z);
01893 return x;
01894 }
01895
01896 uint32 Item::I_getY(const uint8* args, unsigned int )
01897 {
01898 ARG_ITEM_FROM_PTR(item);
01899 if (!item) return 0;
01900
01901 sint32 x,y,z;
01902 item->getLocationAbsolute(x,y,z);
01903 return y;
01904 }
01905
01906 uint32 Item::I_getZ(const uint8* args, unsigned int )
01907 {
01908 ARG_ITEM_FROM_PTR(item);
01909 if (!item) return 0;
01910
01911 sint32 x,y,z;
01912 item->getLocationAbsolute(x,y,z);
01913 return z;
01914 }
01915
01916 uint32 Item::I_getCX(const uint8* args, unsigned int )
01917 {
01918 ARG_ITEM_FROM_PTR(item);
01919 if (!item) return 0;
01920
01921 sint32 x,y,z;
01922 item->getLocationAbsolute(x,y,z);
01923
01924 if (item->flags & FLG_FLIPPED)
01925 return x - item->getShapeInfo()->y * 16;
01926 else
01927 return x - item->getShapeInfo()->x * 16;
01928 }
01929
01930 uint32 Item::I_getCY(const uint8* args, unsigned int )
01931 {
01932 ARG_ITEM_FROM_PTR(item);
01933 if (!item) return 0;
01934
01935 sint32 x,y,z;
01936 item->getLocationAbsolute(x,y,z);
01937
01938 if (item->flags & FLG_FLIPPED)
01939 return y - item->getShapeInfo()->x * 16;
01940 else
01941 return y - item->getShapeInfo()->y * 16;
01942 }
01943
01944 uint32 Item::I_getCZ(const uint8* args, unsigned int )
01945 {
01946 ARG_ITEM_FROM_PTR(item);
01947 if (!item) return 0;
01948
01949 sint32 x,y,z;
01950 item->getLocationAbsolute(x,y,z);
01951
01952 return z + item->getShapeInfo()->z * 4;
01953 }
01954
01955 uint32 Item::I_getPoint(const uint8* args, unsigned int )
01956 {
01957 ARG_ITEM_FROM_PTR(item);
01958 ARG_UC_PTR(ptr);
01959 if (!item) return 0;
01960
01961 sint32 x,y,z;
01962 item->getLocationAbsolute(x,y,z);
01963
01964 WorldPoint point;
01965 point.setX(x);
01966 point.setY(y);
01967 point.setZ(z);
01968
01969 UCMachine::get_instance()->assignPointer(ptr, point.buf, 5);
01970
01971 return 0;
01972 }
01973
01974 uint32 Item::I_getShape(const uint8* args, unsigned int )
01975 {
01976 ARG_ITEM_FROM_PTR(item);
01977 if (!item) return 0;
01978
01979 return item->getShape();
01980 }
01981
01982 uint32 Item::I_setShape(const uint8* args, unsigned int )
01983 {
01984 ARG_ITEM_FROM_PTR(item);
01985 ARG_UINT16(shape);
01986 if (!item) return 0;
01987
01988 item->setShape(shape);
01989 return 0;
01990 }
01991
01992 uint32 Item::I_getFrame(const uint8* args, unsigned int )
01993 {
01994 ARG_ITEM_FROM_PTR(item);
01995 if (!item) return 0;
01996
01997 return item->getFrame();
01998 }
01999
02000 uint32 Item::I_setFrame(const uint8* args, unsigned int )
02001 {
02002 ARG_ITEM_FROM_PTR(item);
02003 ARG_UINT16(frame);
02004 if (!item) return 0;
02005
02006 item->setFrame(frame);
02007 return 0;
02008 }
02009
02010 uint32 Item::I_getQuality(const uint8* args, unsigned int )
02011 {
02012 ARG_ITEM_FROM_PTR(item);
02013 if (!item) return 0;
02014
02015 if (item->getFamily() == ShapeInfo::SF_QUALITY)
02016 return item->getQuality();
02017 else
02018 return 0;
02019 }
02020
02021 uint32 Item::I_getUnkEggType(const uint8* args, unsigned int )
02022 {
02023 ARG_ITEM_FROM_PTR(item);
02024 if (!item) return 0;
02025
02026 if (item->getFamily() == ShapeInfo::SF_UNKEGG) {
02027 if (GAME_IS_U8) {
02028 return item->getQuality();
02029 } else {
02030 return item->getQuality() & 0xFF;
02031 }
02032 } else {
02033 return 0;
02034 }
02035 }
02036
02037 uint32 Item::I_getQuantity(const uint8* args, unsigned int )
02038 {
02039 ARG_ITEM_FROM_PTR(item);
02040 if (!item) return 0;
02041
02042 if (item->getFamily() == ShapeInfo::SF_QUANTITY ||
02043 item->getFamily() == ShapeInfo::SF_REAGENT)
02044 return item->getQuality();
02045 else
02046 return 0;
02047 }
02048
02049 uint32 Item::I_getContainer(const uint8* args, unsigned int )
02050 {
02051 ARG_ITEM_FROM_PTR(item);
02052 if (!item) return 0;
02053
02056
02057 if (item->getParent())
02058 return item->getParent();
02059 else
02060 return 0;
02061 }
02062
02063 uint32 Item::I_getRootContainer(const uint8* args, unsigned int )
02064 {
02065 ARG_ITEM_FROM_PTR(item);
02066 if (!item) return 0;
02067
02068 Container *parent = item->getParentAsContainer();
02069
02072
02073 if (!parent) return 0;
02074
02075 while (parent->getParentAsContainer()) {
02076 parent = parent->getParentAsContainer();
02077 }
02078
02079 return parent->getObjId();
02080 }
02081
02082 uint32 Item::I_getQ(const uint8* args, unsigned int )
02083 {
02084 ARG_ITEM_FROM_PTR(item);
02085 if (!item) return 0;
02086
02087 return item->getQuality();
02088 }
02089
02090 uint32 Item::I_getQLo(const uint8* args, unsigned int )
02091 {
02092 ARG_ITEM_FROM_PTR(item);
02093 if (!item) return 0;
02094
02095 return item->getQuality() & 0xFF;
02096 }
02097
02098 uint32 Item::I_getQHi(const uint8* args, unsigned int )
02099 {
02100 ARG_ITEM_FROM_PTR(item);
02101 if (!item) return 0;
02102
02103 return (item->getQuality() >> 8) & 0xFF;
02104 }
02105
02106 uint32 Item::I_setQ(const uint8* args, unsigned int )
02107 {
02108 ARG_ITEM_FROM_PTR(item);
02109 ARG_UINT16(q);
02110 if (!item) return 0;
02111
02112 item->setQuality(q);
02113 return 0;
02114 }
02115
02116 uint32 Item::I_setQLo(const uint8* args, unsigned int )
02117 {
02118 ARG_ITEM_FROM_PTR(item);
02119 ARG_UINT16(q);
02120 if (!item) return 0;
02121
02122 uint16 iq = item->getQuality() & 0xFF00;
02123
02124 item->setQuality(iq | (q & 0xFF));
02125 return 0;
02126 }
02127
02128 uint32 Item::I_setQHi(const uint8* args, unsigned int )
02129 {
02130 ARG_ITEM_FROM_PTR(item);
02131 ARG_UINT16(q);
02132 if (!item) return 0;
02133
02134 uint16 iq = item->getQuality() & 0x00FF;
02135
02136 item->setQuality(iq | ((q<<8) & 0xFF00));
02137 return 0;
02138 }
02139
02140 uint32 Item::I_setQuality(const uint8* args, unsigned int )
02141 {
02142 ARG_ITEM_FROM_PTR(item);
02143 ARG_UINT16(q);
02144 if (!item) return 0;
02145
02146 if (item->getFamily() != ShapeInfo::SF_GENERIC)
02147 item->setQuality(q);
02148
02149 return 0;
02150 }
02151
02152 uint32 Item::I_setQuantity(const uint8* args, unsigned int )
02153 {
02154 ARG_ITEM_FROM_PTR(item);
02155 ARG_UINT16(q);
02156 if (!item) return 0;
02157
02158 if (item->getFamily() == ShapeInfo::SF_QUANTITY ||
02159 item->getFamily() == ShapeInfo::SF_REAGENT)
02160 item->setQuality(q);
02161
02162 return 0;
02163 }
02164
02165 uint32 Item::I_getFamily(const uint8* args, unsigned int )
02166 {
02167 ARG_ITEM_FROM_PTR(item);
02168 if (!item) return 0;
02169
02170 return item->getFamily();
02171 }
02172
02173 uint32 Item::I_getTypeFlag(const uint8* args, unsigned int )
02174 {
02175 ARG_ITEM_FROM_PTR(item);
02176 ARG_UINT16(typeflag);
02177 if (!item) return 0;
02178
02179 ShapeInfo *info = item->getShapeInfo();
02180
02181 if (GAME_IS_U8 && typeflag >= 64)
02182 perr << "Invalid TypeFlag greater than 63 requested (" << typeflag << ") by Usecode" << std::endl;
02183 if (GAME_IS_CRUSADER && typeflag >= 72)
02184 perr << "Invalid TypeFlag greater than 63 requested (" << typeflag << ") by Usecode" << std::endl;
02185
02186 if (info->getTypeFlag(typeflag))
02187 return 1;
02188 else
02189 return 0;
02190 }
02191
02192 uint32 Item::I_getStatus(const uint8* args, unsigned int )
02193 {
02194 ARG_ITEM_FROM_PTR(item);
02195 if (!item) return 0;
02196
02197 return item->getFlags();
02198 }
02199
02200 uint32 Item::I_orStatus(const uint8* args, unsigned int )
02201 {
02202 ARG_ITEM_FROM_PTR(item);
02203 ARG_UINT16(mask);
02204 if (!item) return 0;
02205
02206 item->flags |= mask;
02207 return 0;
02208 }
02209
02210 uint32 Item::I_andStatus(const uint8* args, unsigned int )
02211 {
02212 ARG_ITEM_FROM_PTR(item);
02213 ARG_UINT16(mask);
02214 if (!item) return 0;
02215
02216 item->flags &= mask;
02217 return 0;
02218 }
02219
02220 uint32 Item::I_ascend(const uint8* args, unsigned int )
02221 {
02222 ARG_ITEM_FROM_PTR(item);
02223 ARG_SINT16(delta);
02224 if (!item) return 0;
02225
02226 int dist = item->ascend(delta);
02227
02228 if (dist == 0x4000)
02229 return 1;
02230 else
02231 return 0;
02232 }
02233
02234 uint32 Item::I_getWeight(const uint8* args, unsigned int )
02235 {
02236 ARG_ITEM_FROM_PTR(item);
02237 if (!item) return 0;
02238
02239 return item->getWeight();
02240 }
02241
02242 uint32 Item::I_getWeightIncludingContents(const uint8* args,
02243 unsigned int )
02244 {
02245 ARG_ITEM_FROM_PTR(item);
02246 if (!item) return 0;
02247
02248 return item->getTotalWeight();
02249 }
02250
02251 uint32 Item::I_bark(const uint8* args, unsigned int )
02252 {
02253 ARG_ITEM_FROM_PTR(item);
02254 ARG_STRING(str);
02255 if (id_item == 666) item = getItem(1);
02256 if (!item) return 0;
02257
02258 uint32 shapenum = item->getShape();
02259 if (id_item == 666) shapenum = 666;
02260 Gump *gump = new BarkGump(item->getObjId(), str, shapenum);
02261
02262 if (item->getObjId() < 256)
02263 {
02264 GumpNotifyProcess* notifyproc;
02265 notifyproc = new ActorBarkNotifyProcess(item->getObjId());
02266 Kernel::get_instance()->addProcess(notifyproc);
02267 gump->SetNotifyProcess(notifyproc);
02268 }
02269
02270 gump->InitGump(0);
02271
02272 return gump->GetNotifyProcess()->getPid();
02273 }
02274
02275 uint32 Item::I_look(const uint8* args, unsigned int )
02276 {
02277 ARG_ITEM_FROM_PTR(item);
02278 if (!item) return 0;
02279
02280 return item->callUsecodeEvent_look();
02281 }
02282
02283 uint32 Item::I_use(const uint8* args, unsigned int )
02284 {
02285 ARG_ITEM_FROM_PTR(item);
02286 if (!item) return 0;
02287
02288 return item->callUsecodeEvent_use();
02289 }
02290
02291 uint32 Item::I_gotHit(const uint8* args, unsigned int )
02292 {
02293 ARG_ITEM_FROM_PTR(item);
02294 ARG_UINT16(hitter);
02295 ARG_SINT16(unk);
02296 if (!item) return 0;
02297
02298 return item->callUsecodeEvent_gotHit(hitter, unk);
02299 }
02300
02301
02302 uint32 Item::I_enterFastArea(const uint8* args, unsigned int )
02303 {
02304 ARG_ITEM_FROM_PTR(item);
02305 if (!item) return 0;
02306
02307 return item->callUsecodeEvent_enterFastArea();
02308 }
02309
02310 uint32 Item::I_ask(const uint8* args, unsigned int )
02311 {
02312 ARG_NULL32();
02313 ARG_LIST(answers);
02314
02315 if (!answers) return 0;
02316
02317
02318 Gump *gump = new AskGump(1, answers);
02319 gump->InitGump(0);
02320 return gump->GetNotifyProcess()->getPid();
02321 }
02322
02323 uint32 Item::I_legalCreateAtPoint(const uint8* args, unsigned int )
02324 {
02325 ARG_UC_PTR(itemptr);
02326 ARG_UINT16(shape);
02327 ARG_UINT16(frame);
02328 ARG_WORLDPOINT(point);
02329
02330
02331 CurrentMap* cm = World::get_instance()->getCurrentMap();
02332 bool valid = cm->isValidPosition(point.getX(), point.getY(), point.getZ(),
02333 shape, 0, 0, 0);
02334 if (!valid)
02335 return 0;
02336
02337 Item* newitem = ItemFactory::createItem(shape, frame, 0, 0, 0, 0, 0, true);
02338 if (!newitem) {
02339 perr << "I_legalCreateAtPoint failed to create item (" << shape
02340 << "," << frame << ")." << std::endl;
02341 return 0;
02342 }
02343 uint16 objID = newitem->getObjId();
02344 newitem->move(point.getX(), point.getY(), point.getZ());
02345
02346 uint8 buf[2];
02347 buf[0] = static_cast<uint8>(objID);
02348 buf[1] = static_cast<uint8>(objID >> 8);
02349 UCMachine::get_instance()->assignPointer(itemptr, buf, 2);
02350
02351 return 1;
02352 }
02353
02354 uint32 Item::I_legalCreateAtCoords(const uint8* args, unsigned int )
02355 {
02356 ARG_UC_PTR(itemptr);
02357 ARG_UINT16(shape);
02358 ARG_UINT16(frame);
02359 ARG_UINT16(x);
02360 ARG_UINT16(y);
02361 ARG_UINT16(z);
02362
02363
02364 CurrentMap* cm = World::get_instance()->getCurrentMap();
02365 bool valid = cm->isValidPosition(x, y, z, shape, 0, 0, 0);
02366 if (!valid)
02367 return 0;
02368
02369
02370 Item* newitem = ItemFactory::createItem(shape, frame, 0, 0, 0, 0, 0, true);
02371 if (!newitem) {
02372 perr << "I_legalCreateAtCoords failed to create item (" << shape
02373 << "," << frame << ")." << std::endl;
02374 return 0;
02375 }
02376 uint16 objID = newitem->getObjId();
02377 newitem->move(x, y, z);
02378
02379 uint8 buf[2];
02380 buf[0] = static_cast<uint8>(objID);
02381 buf[1] = static_cast<uint8>(objID >> 8);
02382 UCMachine::get_instance()->assignPointer(itemptr, buf, 2);
02383
02384 return 1;
02385 }
02386
02387 uint32 Item::I_legalCreateInCont(const uint8* args, unsigned int )
02388 {
02389 ARG_UC_PTR(itemptr);
02390 ARG_UINT16(shape);
02391 ARG_UINT16(frame);
02392 ARG_CONTAINER_FROM_ID(container);
02393 ARG_UINT16(unknown);
02394
02395 uint8 buf[2];
02396 buf[0] = 0;
02397 buf[1] = 0;
02398 UCMachine::get_instance()->assignPointer(itemptr, buf, 2);
02399
02400
02401
02402
02403 Item* newitem = ItemFactory::createItem(shape, frame, 0, 0, 0, 0, 0, true);
02404 if (!newitem) {
02405 perr << "I_legalCreateInCont failed to create item (" << shape
02406 << "," << frame << ")." << std::endl;
02407 return 0;
02408 }
02409
02410
02411 if (newitem->moveToContainer(container)) {
02412 uint16 objID = newitem->getObjId();
02413
02414 uint8 buf[2];
02415 buf[0] = static_cast<uint8>(objID);
02416 buf[1] = static_cast<uint8>(objID >> 8);
02417 UCMachine::get_instance()->assignPointer(itemptr, buf, 2);
02418
02419 return 1;
02420 } else {
02421 perr << "I_legalCreateInCont failed to add item to container ("
02422 << container->getObjId() << ")" << std::endl;
02423
02424 newitem->destroy();
02425
02426 return 0;
02427 }
02428 }
02429
02430 uint32 Item::I_destroy(const uint8* args, unsigned int )
02431 {
02432 ARG_ITEM_FROM_PTR(item);
02433 if (!item || item->getObjId() == 1) return 0;
02434
02435 item->destroy();
02436
02437 return 0;
02438 }
02439
02440 uint32 Item::I_getFootpadData(const uint8* args, unsigned int )
02441 {
02442 ARG_ITEM_FROM_PTR(item);
02443 ARG_UC_PTR(xptr);
02444 ARG_UC_PTR(yptr);
02445 ARG_UC_PTR(zptr);
02446 if (!item) return 0;
02447
02448 uint8 buf[2];
02449 sint32 x,y,z;
02450 item->getFootpadData(x,y,z);
02451
02452 buf[0] = static_cast<uint8>(x);
02453 buf[1] = static_cast<uint8>(x >> 8);
02454 UCMachine::get_instance()->assignPointer(xptr, buf, 2);
02455
02456 buf[0] = static_cast<uint8>(y);
02457 buf[1] = static_cast<uint8>(y >> 8);
02458 UCMachine::get_instance()->assignPointer(yptr, buf, 2);
02459
02460 buf[0] = static_cast<uint8>(z);
02461 buf[1] = static_cast<uint8>(z >> 8);
02462 UCMachine::get_instance()->assignPointer(zptr, buf, 2);
02463
02464 return 0;
02465 }
02466
02467 uint32 Item::I_overlaps(const uint8* args, unsigned int )
02468 {
02469 ARG_ITEM_FROM_PTR(item);
02470 ARG_ITEM_FROM_ID(item2);
02471 if (!item) return 0;
02472 if (!item2) return 0;
02473
02474 if (item->overlaps(*item2))
02475 return 1;
02476 else
02477 return 0;
02478 }
02479
02480 uint32 Item::I_overlapsXY(const uint8* args, unsigned int )
02481 {
02482 ARG_ITEM_FROM_PTR(item);
02483 ARG_ITEM_FROM_ID(item2);
02484 if (!item) return 0;
02485 if (!item2) return 0;
02486
02487 if (item->overlapsxy(*item2))
02488 return 1;
02489 else
02490 return 0;
02491 }
02492
02493 uint32 Item::I_isOn(const uint8* args, unsigned int )
02494 {
02495 ARG_ITEM_FROM_PTR(item);
02496 ARG_ITEM_FROM_ID(item2);
02497 if (!item) return 0;
02498 if (!item2) return 0;
02499
02500 if (item->isOn(*item2))
02501 return 1;
02502 else
02503 return 0;
02504 }
02505
02506 uint32 Item::I_getFamilyOfType(const uint8* args, unsigned int )
02507 {
02508 ARG_UINT16(shape);
02509
02510 return GameData::get_instance()->getMainShapes()->
02511 getShapeInfo(shape)->family;
02512 }
02513
02514 uint32 Item::I_push(const uint8* args, unsigned int )
02515 {
02516 ARG_ITEM_FROM_PTR(item);
02517 if (!item) return 0;
02518
02519 item->moveToEtherealVoid();
02520
02521 return 0;
02522 }
02523
02524 uint32 Item::I_create(const uint8* args, unsigned int )
02525 {
02526 ARG_UC_PTR(itemptr);
02527 ARG_UINT16(shape);
02528 ARG_UINT16(frame);
02529
02530 Item* newitem = ItemFactory::createItem(shape, frame, 0, 0, 0, 0, 0, true);
02531 if (!newitem) {
02532 perr << "I_create failed to create item (" << shape
02533 << "," << frame << ")." << std::endl;
02534 return 0;
02535 }
02536 uint16 objID = newitem->getObjId();
02537
02538 #if 0
02539 pout << "Item::create: created item " << objID << " (" << shape
02540 << "," << frame << ")" << std::endl;
02541 #endif
02542
02543 newitem->moveToEtherealVoid();
02544
02545 uint8 buf[2];
02546 buf[0] = static_cast<uint8>(objID);
02547 buf[1] = static_cast<uint8>(objID >> 8);
02548 UCMachine::get_instance()->assignPointer(itemptr, buf, 2);
02549
02550 return 1;
02551 }
02552
02553 uint32 Item::I_pop(const uint8* args, unsigned int )
02554 {
02555 ARG_NULL32();
02556
02557 World* w = World::get_instance();
02558
02559 if (w->etherealEmpty()) return 0;
02560
02561 uint16 objid = w->etherealPeek();
02562 Item* item = getItem(objid);
02563 if (!item) {
02564 w->etherealRemove(objid);
02565 return 0;
02566 }
02567
02568 item->returnFromEtherealVoid();
02569
02570 #if 0
02571 perr << "Popping item to original location: " << item->getShape() << "," << item->getFrame() << std::endl;
02572 #endif
02573
02575
02576 return objid;
02577 }
02578
02579 uint32 Item::I_popToCoords(const uint8* args, unsigned int )
02580 {
02581 ARG_NULL32();
02582 ARG_UINT16(x);
02583 ARG_UINT16(y);
02584 ARG_UINT16(z);
02585
02586 World* w = World::get_instance();
02587
02588 if (w->etherealEmpty()) return 0;
02589
02590 uint16 objid = w->etherealPeek();
02591 Item* item = getItem(objid);
02592 if (!item) {
02593 w->etherealRemove(objid);
02594 return 0;
02595 }
02596
02597 item->move(x, y, z);
02598
02599 #if 0
02600 perr << "Popping item into map: " << item->getShape() << "," << item->getFrame() << " at (" << x << "," << y << "," << z << ")" << std::endl;
02601 #endif
02602
02604
02605 return objid;
02606 }
02607
02608 uint32 Item::I_popToContainer(const uint8* args, unsigned int )
02609 {
02610 ARG_NULL32();
02611 ARG_CONTAINER_FROM_ID(container);
02612
02613 if (!container) {
02614 perr << "Trying to pop item to invalid container (" << id_container << ")." << std::endl;
02615 return 0;
02616 }
02617
02618 World* w = World::get_instance();
02619
02620 if (w->etherealEmpty()) return 0;
02621
02622 uint16 objid = w->etherealPeek();
02623 Item* item = getItem(objid);
02624 if (!item) {
02625 w->etherealRemove(objid);
02626 return 0;
02627 }
02628
02629 item->moveToContainer(container);
02630
02632
02633 return objid;
02634 }
02635
02636 uint32 Item::I_popToEnd(const uint8* args, unsigned int )
02637 {
02638 ARG_NULL32();
02639 ARG_CONTAINER_FROM_ID(container);
02640
02641 if (!container) {
02642 perr << "Trying to pop item to invalid container (" << id_container << ")." << std::endl;
02643 return 0;
02644 }
02645
02646 World* w = World::get_instance();
02647
02648 if (w->etherealEmpty()) return 0;
02649
02650 uint16 objid = w->etherealPeek();
02651 Item* item = getItem(objid);
02652 if (!item) {
02653 w->etherealRemove(objid);
02654 return 0;
02655 }
02656
02657 item->moveToContainer(container);
02658
02660
02663
02664 return objid;
02665 }
02666
02667 uint32 Item::I_move(const uint8* args, unsigned int )
02668 {
02669 ARG_ITEM_FROM_PTR(item);
02670 ARG_UINT16(x);
02671 ARG_UINT16(y);
02672 ARG_UINT16(z);
02673 if (!item) return 0;
02674
02676
02677 item->move(x,y,z);
02678
02679 return 0;
02680 }
02681
02682 uint32 Item::I_legalMoveToPoint(const uint8* args, unsigned int )
02683 {
02684 ARG_ITEM_FROM_PTR(item);
02685 ARG_WORLDPOINT(point);
02686 ARG_UINT16(force);
02687 ARG_UINT16(unknown2);
02688
02690
02691
02692
02693
02694
02695 return item->collideMove(point.getX(), point.getY(), point.getZ(), false, force==1) == 0x4000;
02696
02697 }
02698
02699 uint32 Item::I_legalMoveToContainer(const uint8* args,unsigned int )
02700 {
02701 ARG_ITEM_FROM_PTR(item);
02702 ARG_CONTAINER_FROM_PTR(container);
02703 ARG_UINT16(unknown);
02704
02705
02706 return item->moveToContainer(container, true);
02707 }
02708
02709 uint32 Item::I_getEtherealTop(const uint8* , unsigned int )
02710 {
02711 World* w = World::get_instance();
02712 if (w->etherealEmpty()) return 0;
02713 return w->etherealPeek();
02714 }
02715
02716
02718 uint32 Item::I_getMapArray(const uint8* args, unsigned int )
02719 {
02720 ARG_ITEM_FROM_PTR(item);
02721 if (!item) return 0;
02722
02723 return item->getMapNum();
02724 }
02725
02727 uint32 Item::I_setMapArray(const uint8* args, unsigned int )
02728 {
02729 ARG_ITEM_FROM_PTR(item);
02730 ARG_UINT16(mapnum);
02731 if (!item) return 0;
02732
02733 item->setMapNum(mapnum);
02734 return 0;
02735 }
02736
02737 uint32 Item::I_getNpcNum(const uint8* args, unsigned int )
02738 {
02739 ARG_ITEM_FROM_PTR(item);
02740 if (!item) return 0;
02741
02742 return item->getNpcNum();
02743 }
02744
02745 uint32 Item::I_getDirToCoords(const uint8* args, unsigned int )
02746 {
02747 ARG_ITEM_FROM_PTR(item);
02748 ARG_UINT16(x);
02749 ARG_UINT16(y);
02750 if (!item) return 0;
02751
02752 sint32 ix,iy,iz;
02753 item->getLocationAbsolute(ix,iy,iz);
02754
02755 return Get_WorldDirection(y - iy, x - ix);
02756 }
02757
02758 uint32 Item::I_getDirFromCoords(const uint8* args, unsigned int )
02759 {
02760 ARG_ITEM_FROM_PTR(item);
02761 ARG_UINT16(x);
02762 ARG_UINT16(y);
02763 if (!item) return 0;
02764
02765 sint32 ix,iy,iz;
02766 item->getLocationAbsolute(ix,iy,iz);
02767
02768 return Get_WorldDirection(iy - y, ix - x);
02769 }
02770
02771 uint32 Item::I_getDirToItem(const uint8* args, unsigned int )
02772 {
02773 ARG_ITEM_FROM_PTR(item);
02774 ARG_ITEM_FROM_ID(item2);
02775 if (!item) return 0;
02776 if (!item2) return 0;
02777
02778 sint32 ix,iy,iz;
02779 item->getLocationAbsolute(ix,iy,iz);
02780
02781 sint32 i2x,i2y,i2z;
02782 item2->getLocationAbsolute(i2x,i2y,i2z);
02783
02784 return Get_WorldDirection(i2y - iy, i2x - ix);
02785 }
02786
02787 uint32 Item::I_getDirFromItem(const uint8* args, unsigned int )
02788 {
02789 ARG_ITEM_FROM_PTR(item);
02790 ARG_ITEM_FROM_ID(item2);
02791 if (!item) return 0;
02792 if (!item2) return 0;
02793
02794 sint32 ix,iy,iz;
02795 item->getLocationAbsolute(ix,iy,iz);
02796
02797 sint32 i2x,i2y,i2z;
02798 item2->getLocationAbsolute(i2x,i2y,i2z);
02799
02800 return Get_WorldDirection(iy - i2y, ix - i2x);
02801 }
02802
02803 uint32 Item::I_hurl(const uint8* args, unsigned int )
02804 {
02805 ARG_ITEM_FROM_PTR(item);
02806 ARG_SINT16(xs);
02807 ARG_SINT16(ys);
02808 ARG_SINT16(zs);
02809 ARG_SINT16(grav);
02810 if (!item) return 0;
02811
02812 item->hurl(xs, ys, zs, grav);
02813
02814 return item->gravitypid;
02815 }
02816
02817 uint32 Item::I_shoot(const uint8* args, unsigned int )
02818 {
02819 ARG_ITEM_FROM_PTR(item);
02820 ARG_WORLDPOINT(point);
02821 ARG_UINT16(speed);
02822 ARG_UINT16(gravity);
02823 if (!item) return 0;
02824
02825 MissileTracker tracker(item, point.getX(), point.getY(), point.getZ(),
02826 speed, gravity);
02827 tracker.launchItem();
02828
02829 return 0;
02830 }
02831
02832 uint32 Item::I_fall(const uint8* args, unsigned int )
02833 {
02834 ARG_ITEM_FROM_PTR(item);
02835 if (!item) return 0;
02836
02837 item->fall();
02838
02839 return 0;
02840 }
02841
02842 uint32 Item::I_grab(const uint8* args, unsigned int )
02843 {
02844 ARG_ITEM_FROM_PTR(item);
02845 if (!item) return 0;
02846
02847 item->grab();
02848
02849 return 0;
02850 }
02851
02852 uint32 Item::I_getSliderInput(const uint8* args, unsigned int )
02853 {
02854 ARG_NULL32();
02855 ARG_SINT16(minval);
02856 ARG_SINT16(maxval);
02857 ARG_SINT16(step);
02858
02859 UCProcess* current = p_dynamic_cast<UCProcess*>(Kernel::get_instance()->getRunningProcess());
02860 assert(current);
02861
02862
02863
02864 SliderGump* gump = new SliderGump(100, 100, minval, maxval, minval, step);
02865 gump->InitGump(0);
02866 gump->setUsecodeNotify(current);
02867
02868 current->suspend();
02869
02870 return 0;
02871 }
02872
02873 uint32 Item::I_openGump(const uint8* args, unsigned int )
02874 {
02875 ARG_ITEM_FROM_PTR(item);
02876 ARG_UINT16(gumpshape);
02877 if (!item) return 0;
02878
02879 item->openGump(gumpshape);
02880 return 0;
02881 }
02882
02883 uint32 Item::I_closeGump(const uint8* args, unsigned int )
02884 {
02885 ARG_ITEM_FROM_PTR(item);
02886 if (!item) return 0;
02887
02888 item->closeGump();
02889 return 0;
02890 }
02891
02892 uint32 Item::I_guardianBark(const uint8* args, unsigned int )
02893 {
02894 ARG_ITEM_FROM_PTR(item);
02895 ARG_UINT16(num);
02896 if (!item) return 0;
02897
02898 return item->callUsecodeEvent_guardianBark(num);
02899 }
02900
02901 uint32 Item::I_getSurfaceWeight(const uint8* args, unsigned int )
02902 {
02903 ARG_ITEM_FROM_PTR(item);
02904 if (!item) return 0;
02905
02906 UCList uclist(2);
02907 LOOPSCRIPT(script, LS_TOKEN_TRUE);
02908 World* world = World::get_instance();
02909 world->getCurrentMap()->surfaceSearch(&uclist, script, sizeof(script),
02910 item, true, false, true);
02911
02912 uint32 weight = 0;
02913 for (uint32 i = 0; i < uclist.getSize(); i++)
02914 {
02915 Item *other = getItem(uclist.getuint16(i));
02916 if (!other) continue;
02917 weight += other->getTotalWeight();
02918 }
02919
02920 return weight;
02921 }
02922
02923 uint32 Item::I_isExplosive(const uint8* args, unsigned int )
02924 {
02925 ARG_ITEM_FROM_PTR(item);
02926 if (!item) return 0;
02927 return item->getShapeInfo()->is_explode()?1:0;
02928 }
02929
02930 uint32 Item::I_receiveHit(const uint8* args, unsigned int )
02931 {
02932 ARG_ITEM_FROM_PTR(item);
02933 ARG_UINT16(other);
02934 ARG_SINT16(dir);
02935 ARG_SINT16(damage);
02936 ARG_UINT16(type);
02937 if (!item) return 0;
02938
02939 item->receiveHit(other, dir, damage, type);
02940
02941 return 0;
02942 }
02943
02944 uint32 Item::I_explode(const uint8* args, unsigned int )
02945 {
02946 ARG_ITEM_FROM_PTR(item);
02947 if (!item) return 0;
02948
02949 item->explode();
02950 return 0;
02951 }
02952
02953 uint32 Item::I_igniteChaos(const uint8* args, unsigned int )
02954 {
02955 ARG_UINT16(x);
02956 ARG_UINT16(y);
02957 ARG_NULL8();
02958
02959 UCList itemlist(2);
02960 LOOPSCRIPT(script, LS_SHAPE_EQUAL(592));
02961 CurrentMap* currentmap = World::get_instance()->getCurrentMap();
02962 currentmap->areaSearch(&itemlist, script, sizeof(script), 0,
02963 160, false, x, y);
02964
02965 for (unsigned int i = 0; i < itemlist.getSize(); ++i) {
02966 Item *item = getItem(itemlist.getuint16(i));
02967 if (!item) continue;
02968 item->use();
02969 }
02970
02971 return 0;
02972 }
02973
02974 uint32 Item::I_canReach(const uint8* args, unsigned int )
02975 {
02976 ARG_ITEM_FROM_PTR(item);
02977 ARG_ITEM_FROM_ID(other);
02978 ARG_SINT16(range);
02979
02980
02981
02982 if (item->canReach(other, range))
02983 return 1;
02984 else
02985 return 0;
02986 }
02987
02988
02989 uint32 Item::I_getRange(const uint8* args, unsigned int )
02990 {
02991 ARG_ITEM_FROM_PTR(item);
02992 ARG_ITEM_FROM_ID(other);
02993 if (!item) return 0;
02994 if (!other) return 0;
02995
02996 return item->getRange(*other);
02997 }
02998
02999 uint32 Item::I_isCrusTypeNPC(const uint8* args, unsigned int )
03000 {
03001 ARG_UINT16(sh);
03002
03003 if (sh == 0x7FE) return 1;
03004
03005 ShapeInfo* info;
03006 info = GameData::get_instance()->getMainShapes()->getShapeInfo(sh);
03007 if (!info) return 0;
03008
03009 if (info->flags & ShapeInfo::SI_CRUS_NPC)
03010 return 1;
03011 else
03012 return 0;
03013 }