Item.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2007 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 
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 // p_dynamic_cast stuff
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         // No parent, no container
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         // It's currently in the ethereal void, remove it from there
00150         if (flags & FLG_ETHEREAL) {
00151 
00152                 // Remove us from the ethereal void
00153                 World::get_instance()->etherealRemove(objid);
00154         }
00155 
00156         // Remove from container (if contained or equiped)
00157         if (flags & (FLG_CONTAINED|FLG_EQUIPPED))
00158         {
00159                 if (parent) {
00160                         // If we are flagged as Ethereal, we are already removed 
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                 // Clear our owner. 
00170                 parent = 0;
00171 
00172                 // No lerping when going from a container to somewhere else
00173                 no_lerping = true;
00174         }
00175         // Item needs to be removed if it in the map, and it is moving to a 
00176         // different chunk
00177         else if ((extendedflags & EXT_INCURMAP) && 
00178                         ((x / mapChunkSize != X / mapChunkSize) || 
00179                         (y / mapChunkSize != Y / mapChunkSize))) {
00180 
00181                 // Remove us from the map
00182                 map->removeItem(this);
00183         }
00184 
00185         // Unset all the various flags that no longer apply
00186         flags &= ~(FLG_CONTAINED|FLG_EQUIPPED|FLG_ETHEREAL);
00187 
00188         // Set the location
00189         x = X;
00190         y = Y;
00191         z = Z;
00192 
00193         // Add it to the map if needed
00194         if (!(extendedflags & EXT_INCURMAP))
00195         {
00196                 // Disposable fast only items get put at the end
00197                 // While normal items get put at start
00198                 if (flags & (FLG_DISPOSABLE|FLG_FAST_ONLY))
00199                         map->addItemToEnd(this);
00200                 else
00201                         map->addItem(this);
00202         }
00203 
00204         // Call just moved
00205         callUsecodeEvent_justMoved();
00206 
00207         // Are we moving somewhere fast
00208         bool dest_fast = map->isChunkFast(X/mapChunkSize, Y/mapChunkSize);
00209 
00210         // No lerping for this move
00211         if (no_lerping) extendedflags |= EXT_LERP_NOPREV;
00212 
00213         // If the destination is not in the fast area, and we are in
00214         // the fast area, we need to call leaveFastArea, as long as we aren't
00215         // being followed by the camera. We also disable lerping in such a case
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; //we are done
00224         }
00225         // Or if the dest is fast, and we are not, we need to call enterFastArea
00226         else if (dest_fast && !(flags & Item::FLG_FASTAREA)) {
00227                 extendedflags |= EXT_LERP_NOPREV;
00228                 enterFastArea();
00229         }
00230 
00231         // If we are being followed, notify the camera that we moved
00232         // Note that we don't need to 
00233         if (extendedflags & EXT_CAMERA)
00234                 CameraProcess::GetCameraProcess()->ItemMoved();
00235 }
00236 
00237 bool Item::moveToContainer(Container *container, bool checkwghtvol)
00238 {
00239         // Null container, report an error message
00240         if (!container) {
00241                 perr << "NULL container passed to Item::moveToContainer" << std::endl;
00242                 return false;
00243         }
00244 
00245         // Already there, do nothing, but only if not ethereal
00246         bool ethereal_same = false;
00247         if ( container->getObjId() == parent ) {
00248                 // If we are ethereal we'd like to know if we are just being moved back
00249                 if (flags & FLG_ETHEREAL) ethereal_same = true;
00250                 else return true;
00251         }
00252 
00253         // Eh, can't do it
00254         if (!container->CanAddItem(this,checkwghtvol)) return false;
00255 
00256         // It's currently in the ethereal void
00257         if (flags & FLG_ETHEREAL) {
00258 
00259                 // Remove us from the ethereal void
00260                 World::get_instance()->etherealRemove(objid);
00261         }
00262 
00263         // Remove from container (if contained or equiped)
00264         if (flags & (FLG_CONTAINED|FLG_EQUIPPED))
00265         {
00266                 if (parent) {
00267                         // If we are flagged as Ethereal, we are already removed 
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                 // Clear our owner. 
00277                 parent = 0;
00278         }
00279         // Item needs to be removed if it in the map
00280         else if (extendedflags & EXT_INCURMAP) {
00281 
00282                 // Remove us from the map
00283                 World::get_instance()->getCurrentMap()->removeItem(this);
00284         }
00285 
00286         // Unset all the various flags that no longer apply
00287         flags &= ~(FLG_CONTAINED|FLG_EQUIPPED|FLG_ETHEREAL);
00288 
00289         // Set location to 0,0,0 if we aren't an ethereal item moving back
00290         if (!ethereal_same) x = y = 0;
00291         z = 0;
00292 
00293         // Add the item, don't bother with checking weight or vol since we already
00294         // know if it will fit or not
00295         container->addItem(this, false);
00296         
00297         // Set our owner. 
00298         parent = container->getObjId();
00299 
00300         // Set us contained
00301         flags |= FLG_CONTAINED;
00302 
00303         // If moving to avatar, mark as OWNED
00304         Item *p = this;
00305         while (p->getParentAsContainer())
00306                 p = p->getParentAsContainer();
00307         // In Avatar's inventory?
00308         if (p->getObjId() == 1)
00309                 setFlagRecursively(FLG_OWNED);
00310         
00311         // No lerping when moving to a container
00312         extendedflags |= EXT_LERP_NOPREV;
00313 
00314         // Call just moved
00315         callUsecodeEvent_justMoved();
00316 
00317         // For a container, it's fast if it's got a gump open
00318         bool dest_fast = (container->flags & FLG_GUMP_OPEN)!=0;
00319 
00320         // If the destination is not in the fast area, and we are in
00321         // the fast area, we need to call leaveFastArea
00322         if (!dest_fast && (flags & Item::FLG_FASTAREA))
00323                 leaveFastArea();
00324         // Or if the dest is fast, and we are not, we need to call enterFastArea
00325         else if (dest_fast && !(flags & Item::FLG_FASTAREA))
00326                 enterFastArea();
00327 
00328         // Done
00329         return true;
00330 }
00331 
00332 void Item::moveToEtherealVoid()
00333 {
00334         // It's already Ethereal
00335         if (flags & FLG_ETHEREAL) return;
00336 
00337         // Add it to the ethereal void
00338         World::get_instance()->etherealPush(objid);
00339 
00340         // It's owned by something removed it from the something, but keep flags
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         // Set the ETHEREAL Flag
00356         flags |=  FLG_ETHEREAL;
00357 }
00358 
00359 void Item::returnFromEtherealVoid()
00360 {
00361         // It's not Ethereal
00362         if (!(flags & FLG_ETHEREAL)) return;
00363 
00364         // Ok, we can do 2 things here
00365         // If an item has the contained or Equipped flags set, we return it to it's owner
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         // or we return it to the world
00375         else {
00376                 move(x,y,z);
00377         }
00378 
00379 }
00380 
00381 void Item::movedByPlayer()
00382 {
00383         // owned-by-avatar items can't be stolen
00384         if (flags & FLG_OWNED) return;
00385 
00386         // Otherwise, player is stealing.
00387         // See if anybody is around to notice.
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         // This sets the coordinates to (255,255) and lets the ContainerGump
00443         // randomize the position when it is next opened.
00444         y = 0xFFFF;
00445 }
00446 
00447 void Item::getCentre(sint32& X, sint32& Y, sint32& Z) const
00448 {
00449         // constants!
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         // invisible items (trap markers and such) don't take up volume
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         // if really necessary this could be made static to prevent news/deletes
00658         DynamicUCStack stack(0x40); // 64bytes should be plenty of room
00659 
00660         unsigned int i = 0;
00661 
00662         uint16 ui16a, ui16b;
00663 
00664         stack.push2(1); // default to true if script is empty
00665 
00666         while (i < scriptsize) {
00667                 switch(script[i]) {
00668                 case LS_TOKEN_FALSE: // false
00669                         stack.push2(0); break;
00670 
00671                 case LS_TOKEN_TRUE: // true
00672                         stack.push2(1); break;
00673 
00674                 case LS_TOKEN_END: // end
00675                         ui16a = stack.pop2();
00676                         return (ui16a != 0);
00677 
00678                 case LS_TOKEN_INT: // 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: // 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: // 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: // 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: // item status
00712                         stack.push2(getFlags());
00713                         break;
00714 
00715                 case LS_TOKEN_Q: // item quality
00716                         stack.push2(getQuality());
00717                         break;
00718 
00719                 case LS_TOKEN_NPCNUM: // npc num
00720                         stack.push2(getNpcNum());
00721                         break;
00722 
00723                 case LS_TOKEN_EQUAL: // 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: // greater than
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: // less than
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: // greater or equal
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: // smaller or equal
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: // item family
00769                         stack.push2(getFamily());
00770                         break;
00771 
00772                 case LS_TOKEN_SHAPE: // item 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: // item 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                 // If we are moving from a container, only check the destination
00847                 start[0] = end[0];
00848                 start[1] = end[1];
00849                 start[2] = end[2];
00850         }
00851         else
00852         {
00853                 // Otherwise check from where we are to where we want to go
00854                 getLocation(start[0], start[1], start[2]);
00855         }
00856 
00857         sint32 dims[3];
00858         getFootpadWorld(dims[0], dims[1], dims[2]);
00859 
00860         // Do the sweep test
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         // Ok, now to work out what to do
00867 
00868 
00869         // the force of the hit, used for the gotHit/hit usecode calls
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         // if we are contained, we always teleport
00879         if (teleport || parent)
00880         {
00881                 // If teleporting and not force, work out if we can reach the end
00882                 if (!force) 
00883                 {
00884                         for (it = collisions.begin(); it != collisions.end(); it++)
00885                         {
00886                                 // Uh oh, we hit something, can't move
00887                                 if (it->end_time == 0x4000 && !it->touching && it->blocking) {
00888                                         if (hititem) *hititem = it->item;
00889                                         return 0;
00890                                 }
00891                         }
00892                 }
00893 
00894                 // Trigger all the required events
00895                 bool we_were_released = false;
00896                 for (it = collisions.begin(); it != collisions.end(); it++)
00897                 {
00898                         Item *item = getItem(it->item);
00899 
00900                         // Hitting us at the start and end, don't do anything
00901                         if (!parent && it->hit_time == 0x0000 && 
00902                                         it->end_time == 0x4000)
00903                         {
00904                                 continue;
00905                         }
00906                         // Hitting us at the end (call hit on us, got hit on them)
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                         // Hitting us at the start (call release on us and them)
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                 // Call release on us
00925                 if (we_were_released) callUsecodeEvent_release();
00926 
00927                 // Move US!
00928                 move(end[0], end[1], end[2]);
00929 
00930                 // We reached the end
00931                 return 0x4000;
00932         }
00933         else
00934         {
00935                 sint32 hit = 0x4000;
00936 
00937                 // If not force, work out if we can reach the end
00938                 // if not, need to do 'stuff'
00939                 // We don't care about items hitting us at the start
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                 // Trigger all the required events
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                         // Did we go past the endpoint of the move?
00974                         if (it->hit_time > hit) break;
00975 
00976                         uint16 proc_gothit = 0, proc_rel = 0;
00977 
00978                         // If hitting at start, we should have already 
00979                         // called gotHit and hit.
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                         // If not hitting at end, we will need to call release
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                         // We want to make sure that release is called AFTER gotHit.
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                 // Call release on us
01006                 if (we_were_released) callUsecodeEvent_release();
01007 
01008                 // Move US!
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         // Non-monster NPCs use objid/npcnum + 1024
01033         // Note: in the original, a non-monster NPC is specified with
01034         // the FAST_ONLY flag. However, this causes some summoned monster which
01035         // do not receive the FAST_ONLY flag to behave strangely. (Confirmed that
01036         // happens in the original as well.) -wjp 20050128
01037         if (objid < 256 && (extendedflags & EXT_PERMANENT_NPC))
01038                 class_id = objid + 1024;
01039 
01040         // CHECKME: to make Pentagram behave as much like the original as possible,
01041         // don't call any usecode if the original would call the wrong class
01042         if (objid < 256 && !(extendedflags & EXT_PERMANENT_NPC) &&
01043                 !(flags & FLG_FAST_ONLY))
01044                 return 0;
01045 
01046         // UnkEggs have quality+0x47F
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; // event not found
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         // FIXME: Disabled usecode except for Use events in crusader for now
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()                                                    // event 0
01070 {
01071         return callUsecodeEvent(0);     // CONSTANT
01072 }
01073 
01074 uint32 Item::callUsecodeEvent_use()                                                             // event 1
01075 {
01076         return callUsecodeEvent(1);     // CONSTANT
01077 }
01078 
01079 uint32 Item::callUsecodeEvent_anim()                                                    // event 2
01080 {
01081         return callUsecodeEvent(2);     // CONSTANT
01082 }
01083 
01084 uint32 Item::callUsecodeEvent_cachein()                                                 // event 4
01085 {
01086         return callUsecodeEvent(4);     // CONSTANT
01087 }
01088 
01089 uint32 Item::callUsecodeEvent_hit(uint16 hitter, sint16 hitforce)// event 5
01090 {
01091         DynamicUCStack  arg_stack(4);
01092         arg_stack.push2(hitforce);
01093         arg_stack.push2(hitter);
01094         return callUsecodeEvent(5, arg_stack.access(), 4);      // CONSTANT 5
01095 }
01096 
01097 uint32 Item::callUsecodeEvent_gotHit(uint16 hitter, sint16 hitforce)// event 6
01098 {
01099         DynamicUCStack  arg_stack(4);
01100         arg_stack.push2(hitforce);
01101         arg_stack.push2(hitter);
01102         return callUsecodeEvent(6, arg_stack.access(), 4);      // CONSTANT 6
01103 }
01104 
01105 uint32 Item::callUsecodeEvent_hatch()                                                   // event 7
01106 {
01107         return callUsecodeEvent(7);             // CONSTANT
01108 }
01109 
01110 uint32 Item::callUsecodeEvent_schedule(uint32 time)                             // event 8
01111 {
01112         DynamicUCStack  arg_stack(4);
01113         arg_stack.push4(time);
01114         return callUsecodeEvent(8, arg_stack.access(), 4);  // CONSTANT 8
01115 }
01116 
01117 uint32 Item::callUsecodeEvent_release()                                                 // event 9
01118 {
01119         return callUsecodeEvent(9);             // CONSTANT
01120 }
01121 
01122 uint32 Item::callUsecodeEvent_combine()                                                 // event C
01123 {
01124         return callUsecodeEvent(0xC);   // CONSTANT
01125 }
01126 
01127 uint32 Item::callUsecodeEvent_enterFastArea()                                   // event F
01128 {
01129         return callUsecodeEvent(0xF);   // CONSTANT
01130 }
01131 
01132 uint32 Item::callUsecodeEvent_leaveFastArea()                                   // event 10
01133 {
01134         return callUsecodeEvent(0x10);  // CONSTANT
01135 }
01136 
01137 uint32 Item::callUsecodeEvent_cast(uint16 unk)                                  // event 11
01138 {
01139         DynamicUCStack  arg_stack(2);
01140         arg_stack.push2(unk);
01141         return callUsecodeEvent(0x11, arg_stack.access(), 2); // CONSTANT 0x11
01142 }
01143 
01144 uint32 Item::callUsecodeEvent_justMoved()                                               // event 12
01145 {
01146         return callUsecodeEvent(0x12);  // CONSTANT
01147 }
01148 
01149 uint32 Item::callUsecodeEvent_AvatarStoleSomething(uint16 unk)  // event 13
01150 {
01151         DynamicUCStack  arg_stack(2);
01152         arg_stack.push2(unk);
01153         return callUsecodeEvent(0x13, arg_stack.access(), 2); // CONSTANT 0x13
01154 }
01155 
01156 uint32 Item::callUsecodeEvent_guardianBark(sint16 unk)                  // event 15
01157 {
01158         DynamicUCStack  arg_stack(2);
01159         arg_stack.push2(unk);
01160         return callUsecodeEvent(0x15, arg_stack.access(), 2); // CONSTANT 0x15
01161 }
01162 
01163 uint32 Item::use()
01164 {
01165         Actor* actor = p_dynamic_cast<Actor*>(this);
01166         if (actor) {
01167                 if (actor->isDead()) {
01168                         // dead actor, so open/close the dead-body-gump
01169                         if (getFlags() & FLG_GUMP_OPEN) {
01170                                 closeGump();
01171                         } else {
01172                                 openGump(12); // CONSTANT!!
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                 // Remove us from the ether
01185                 World::get_instance()->etherealRemove(objid);
01186         }
01187         else if (parent) {              
01188                 // we're in a container, so remove self from parent
01190                 Container *p = getParentAsContainer();
01191                 if (p) p->removeItem(this);
01192         } else if (extendedflags & EXT_INCURMAP) {
01193                 // remove self from CurrentMap
01194                 World::get_instance()->getCurrentMap()->removeItemFromList(this,x,y);
01195         }
01196                 
01197         if (extendedflags & Item::EXT_CAMERA)
01198                 CameraProcess::SetCameraProcess(0);
01199 
01200         // Do we want to delete now or not?
01201         if (!delnow) {
01202                 Process* dap = new DestroyItemProcess(this);
01203                 Kernel::get_instance()->addProcess(dap);
01204                 return;
01205         }
01206 
01207         clearObjId();
01208         delete this; // delete self.
01209 }
01210 
01211 //
01212 // Item::setupLerp()
01213 //
01214 // Desc: Setup the lerped info for this frame
01215 //
01216 void Item::setupLerp(sint32 gametick)
01217 {
01218         // Don't need to set us up
01219         if (last_setup && gametick == last_setup)
01220                 return;
01221 
01222         // Are we lerping or are we not? Default we lerp.
01223         bool no_lerp = false;
01224 
01225         // No lerping this frame if Shape Changed, or No lerp is set, 
01226         // or no last setup, or last setup more than 1 tick ago
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         // Update the time we were just setup
01233         last_setup = gametick;
01234 
01235         // Clear the flag
01236         extendedflags &= ~EXT_LERP_NOPREV;
01237 
01238         // Animate it, if needed
01239         if ((gametick%3) == (objid%3)) animateItem();
01240 
01241         // Setup the prev values for lerping
01242         if (!no_lerp) l_prev = l_next;
01243 
01244         // Setup next
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         // Setup prev values for not lerping
01259         if (no_lerp) l_prev = l_next;
01260 }
01261 
01262 // Animate the item
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                 // 50 % chance
01279                 if (std::rand() & 1) break;
01280 
01281         case 1:
01282         case 3:
01283                 // 50 % chance
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         //return dirty;
01329 }
01330 
01331 
01332 // Called when an item has entered the fast area
01333 void Item::enterFastArea()
01334 {
01336         if (shape == 0x2c8) return;
01337 
01338         // Call usecode
01339         if (!(flags & FLG_FASTAREA)) {
01340 
01341                 Actor* actor = p_dynamic_cast<Actor*>(this);
01342                 if (actor && actor->isDead()) {
01343                         // dead actor, don't call the usecode
01344                 } else {
01345                         callUsecodeEvent_enterFastArea();
01346                 }
01347         }
01348 
01349         // We're fast!
01350         flags |= FLG_FASTAREA;
01351 }
01352 
01353 // Called when an item is leaving the fast area
01354 void Item::leaveFastArea()
01355 {
01356         // Call usecode
01357         if ((!(flags & FLG_FAST_ONLY) || getShapeInfo()->is_noisy()) && 
01358                         (flags & FLG_FASTAREA))
01359                 callUsecodeEvent_leaveFastArea();
01360 
01361         // If we have a gump open, close it (unless we're in a container)
01362         if (!parent && (flags & FLG_GUMP_OPEN)) 
01363         {
01364                 Gump *g = GUIApp::get_instance()->getGump(gump);
01365                 if (g) g->Close();
01366         }
01367 
01368         // Unset the flag
01369         flags &= ~FLG_FASTAREA;
01370 
01371         // CHECKME: what do we need to do exactly?
01372         // currently,  destroy object
01373 
01374         // Kill us if we are fast only, unless we're in a container
01375         if ((flags & FLG_FAST_ONLY) && !getParent()) {
01376                 // destroy contents if container
01377                 Container* c = p_dynamic_cast<Container*>(this);
01378                 if (c) c->destroyContents();
01379 
01380                 destroy();
01381                 // NB: destroy() creates an DestroyItemProcess to actually
01382                 // delete the item in this case.
01383         }
01384         // If we have a gravity process, move us to the ground
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         // can we already clear gump here, or do we need to wait for the gump
01432         // to really close??
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 //      pout << "Ascend: objid=" << getObjId() << ", delta=" << delta << std::endl;
01446 
01447         if (delta == 0) return 0x4000;
01448 
01449         // * gather all items on top of this item (recursively?)
01450         // * etherealize all those items to get them out of the way
01451         // * move self up/down
01452         // * attempt to rematerialize the items up/down
01453         // (going through etherealness to avoid having to sort the supported items)
01454 
01455         UCList uclist(2);
01456         LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
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         // move self
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 //      pout << "Ascend: dist=" << dist << std::endl;
01476 
01477         // move other items
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); // automatically un-etherealizes item
01488                 } else {
01489                         // uh oh...
01490                         // CHECKME: what do we do here?
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                 // can't fall
01518                 return;
01519         }
01520 
01521         GravityProcess* p = ensureGravityProcess();
01522         p->setGravity(4); 
01523 }
01524 
01525 void Item::grab()
01526 {
01527         // CHECKME: is the fall/release timing correct?
01528 
01529         UCList uclist(2);
01530         LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
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(); // delete self
01579         // WARNING: we are deleted at this point
01580 
01581         UCList itemlist(2);
01582         LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
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; // check vertical distance
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         // first, check if the item has a 'gotHit' usecode event
01612         if (callUsecodeEvent_gotHit(other, 0)) 
01613                 return;
01614 
01615         // explosive?
01616         if (getShapeInfo()->is_explode()) {
01617                 explode(); // warning: deletes this
01618                 return;
01619         }
01620 
01621         // breakable?
01622         if (getFamily() == ShapeInfo::SF_BREAKABLE) {
01623                 // CHECKME: anything else?
01624                 destroy();
01625                 return;
01626         }
01627 
01628         if (getShapeInfo()->is_fixed() || getShapeInfo()->weight == 0) {
01629                 // can't move
01630                 return;
01631         }
01632 
01633         // nothing special, so just hurl the item
01634         // TODO: hurl item in direction, with speed depending on damage
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                 // living actors can't be moved
01647                 if (!actor->isDead()) return false;
01648         }
01649 
01650         // CHECKME: might need more checks here (weight?)
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                 // ignore self and other
01678                 if (it->item == item) continue;
01679                 if (it->item == other && !usingAlternatePos) {
01680                         other_hit_time = it->hit_time;
01681                         continue;
01682                 }
01683 
01684                 // only touching?
01685                 if (it->touching) continue;
01686 
01687                 // hit something 
01688                 if (it->blocking && it->hit_time < blocked_time) {
01689                         blocked_time = it->hit_time;
01690                 }
01691         }
01692 
01693         // 'other' must be the first item that is hit.
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         // get location and dimensions of self and other (or their root containers)
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         // if items are further away than range in any direction, return false
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         // if not, do line of sight between origins of items
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]; // bottom of other between bottom and top of this
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         // if that fails, try line of sight between centers
01751         start[0] = thisX - thisXd/2; // xy center of this
01752         start[1] = thisY - thisYd/2;
01753         start[2] = thisZ;
01754         if (thisZd > 16)
01755                 start[2] += thisZd - 8; // eye height
01756 
01757         end[0] = otherX - otherXd/2; // xyz center of other
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         // if that fails, try line of sight between eye level and top of 2nd
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         // can't merge with self
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         // special cases: necromancy reagents, shape 395
01795         // blood: frame 0-5
01796         // bone: frame 6-7
01797         // wood: frame 8
01798         // dirt: frame 9
01799         // ex.hood: frame 10-12
01800         // blackmoor: frame 14-15
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                 // these only make sense in currently loaded items
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 /*argsize*/)
01877 {
01878         ARG_NULL32(); // ARG_ITEM_FROM_PTR(item);
01879 
01880         // Guess: this is used to make sure an item is painted in the original.
01881         // Our renderer is different, making this intrinsic unnecessary.
01882 
01883         return 0;
01884 }
01885 
01886 uint32 Item::I_getX(const uint8* args, unsigned int /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
02252 {
02253         ARG_ITEM_FROM_PTR(item);
02254         ARG_STRING(str);
02255         if (id_item == 666) item = getItem(1);
02256         if (!item) return 0;    // Hack!
02257 
02258         uint32 shapenum = item->getShape();
02259         if (id_item == 666) shapenum = 666;     // Hack for guardian barks
02260         Gump *gump = new BarkGump(item->getObjId(), str, shapenum);
02261         
02262         if (item->getObjId() < 256) // CONSTANT!
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
02311 {
02312         ARG_NULL32(); // ARG_ITEM_FROM_PTR(item); // currently unused.
02313         ARG_LIST(answers);
02314 
02315         if (!answers) return 0;
02316 
02317         // Use AskGump
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 /*argsize*/)
02324 {
02325         ARG_UC_PTR(itemptr); // need to store the item id at *itemptr
02326         ARG_UINT16(shape);
02327         ARG_UINT16(frame);
02328         ARG_WORLDPOINT(point);
02329 
02330         // check if item can exist
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 /*argsize*/)
02355 {
02356         ARG_UC_PTR(itemptr); // need to store the item id at *itemptr
02357         ARG_UINT16(shape);
02358         ARG_UINT16(frame);
02359         ARG_UINT16(x);
02360         ARG_UINT16(y);
02361         ARG_UINT16(z);
02362 
02363         // check if item can exist
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         // if yes, create it
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 /*argsize*/)
02388 {
02389         ARG_UC_PTR(itemptr); // need to store the item id at *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         // Create an item and try to add it to the given container.
02401         // If it fits, return id; otherwise return 0.
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         // also need to check weight, volume maybe??
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                 // failed to add; clean up
02424                 newitem->destroy();
02425 
02426                 return 0;
02427         }
02428 }
02429 
02430 uint32 Item::I_destroy(const uint8* args, unsigned int /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
02525 {
02526         ARG_UC_PTR(itemptr); // need to store the item id at *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 /*argsize*/)
02554 {
02555         ARG_NULL32(); // ARG_ITEM_FROM_PTR(item); // unused
02556 
02557         World* w = World::get_instance();
02558 
02559         if (w->etherealEmpty()) return 0; // no items left on stack
02560 
02561         uint16 objid = w->etherealPeek();
02562         Item* item = getItem(objid);
02563         if (!item) {
02564                 w->etherealRemove(objid);
02565                 return 0; // top item was invalid
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 /*argsize*/)
02580 {
02581         ARG_NULL32(); // ARG_ITEM_FROM_PTR(item); // unused
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; // no items left on stack
02589 
02590         uint16 objid = w->etherealPeek();
02591         Item* item = getItem(objid);
02592         if (!item) {
02593                 w->etherealRemove(objid);
02594                 return 0; // top item was invalid
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 /*argsize*/)
02609 {
02610         ARG_NULL32(); // ARG_ITEM_FROM_PTR(item); // unused
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; // no items left on stack
02621 
02622         uint16 objid = w->etherealPeek();
02623         Item* item = getItem(objid);
02624         if (!item) {
02625                 w->etherealRemove(objid);
02626                 return 0; // top item was invalid
02627         }
02628 
02629         item->moveToContainer(container);
02630 
02632 
02633         return objid;
02634 }
02635 
02636 uint32 Item::I_popToEnd(const uint8* args, unsigned int /*argsize*/)
02637 {
02638         ARG_NULL32(); // ARG_ITEM_FROM_PTR(item); // unused
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; // no items left on stack
02649 
02650         uint16 objid = w->etherealPeek();
02651         Item* item = getItem(objid);
02652         if (!item) {
02653                 w->etherealRemove(objid);
02654                 return 0; // top item was invalid
02655         }
02656 
02657         item->moveToContainer(container);
02658 
02660 
02663 
02664         return objid;
02665 }
02666 
02667 uint32 Item::I_move(const uint8* args, unsigned int /*argsize*/)
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         //item->collideMove(x, y, z, true, true);
02679         return 0;
02680 }
02681 
02682 uint32 Item::I_legalMoveToPoint(const uint8* args, unsigned int /*argsize*/)
02683 {
02684         ARG_ITEM_FROM_PTR(item);
02685         ARG_WORLDPOINT(point);
02686         ARG_UINT16(force); // 0/1
02687         ARG_UINT16(unknown2); // always 0
02688 
02690 
02691 //      if (item->canExistAt(point.getX(), point.getY(), point.getZ())) {
02692 //              item->move(point.getX(), point.getY(), point.getZ());
02693 //              return 1;
02694 //      } else {
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 /*argsize*/)
02700 {
02701         ARG_ITEM_FROM_PTR(item);
02702         ARG_CONTAINER_FROM_PTR(container);
02703         ARG_UINT16(unknown); // always 0
02704 
02705         // try to move item to container checking weight and volume
02706         return item->moveToContainer(container, true);
02707 }
02708 
02709 uint32 Item::I_getEtherealTop(const uint8* /*args*/, unsigned int /*argsize*/)
02710 {
02711         World* w = World::get_instance();
02712         if (w->etherealEmpty()) return 0; // no items left on stack
02713         return w->etherealPeek();
02714 }
02715 
02716 
02718 uint32 Item::I_getMapArray(const uint8* args, unsigned int /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
02818 {
02819         ARG_ITEM_FROM_PTR(item);
02820         ARG_WORLDPOINT(point);
02821         ARG_UINT16(speed); // either 0x20 (fish) or 0x40 (death disk, dart)
02822         ARG_UINT16(gravity); // either 2 (fish) or 1 (death disk, dart)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
02853 {
02854         ARG_NULL32(); //        ARG_ITEM_FROM_PTR(item);
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 //      pout << "SliderGump: min=" << minval << ", max=" << maxval << ", step=" << step << std::endl;
02863 
02864         SliderGump* gump = new SliderGump(100, 100, minval, maxval, minval, step);
02865         gump->InitGump(0); // modal gump
02866         gump->setUsecodeNotify(current);
02867 
02868         current->suspend();
02869 
02870         return 0;
02871 }
02872 
02873 uint32 Item::I_openGump(const uint8* args, unsigned int /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
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 /*argsize*/)
02931 {
02932         ARG_ITEM_FROM_PTR(item);
02933         ARG_UINT16(other);
02934         ARG_SINT16(dir);
02935         ARG_SINT16(damage); // force of the hit
02936         ARG_UINT16(type); // hit 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 /*argsize*/)
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 /*argsize*/)
02954 {
02955         ARG_UINT16(x);
02956         ARG_UINT16(y);
02957         ARG_NULL8();
02958 
02959         UCList itemlist(2);
02960         LOOPSCRIPT(script, LS_SHAPE_EQUAL(592)); // all oilflasks (CONSTANT!)
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 /*argsize*/)
02975 {
02976         ARG_ITEM_FROM_PTR(item);
02977         ARG_ITEM_FROM_ID(other);
02978         ARG_SINT16(range);
02979 
02980         // TODO: add cheat to make this always return 1
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 /*argsize*/)
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 /*argsize*/)
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 }

Generated on Fri Jul 27 22:27:21 2007 for pentagram by  doxygen 1.4.7