ContainerGump.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2003-2006  The Pentagram Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (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 #include "ContainerGump.h"
00021 
00022 #include "Shape.h"
00023 #include "ShapeFrame.h"
00024 #include "ShapeInfo.h"
00025 #include "Container.h"
00026 #include "RenderSurface.h"
00027 #include "GUIApp.h"
00028 #include "Kernel.h"
00029 #include "GameData.h"
00030 #include "MainShapeArchive.h"
00031 #include "Mouse.h"
00032 #include "SliderGump.h"
00033 #include "GumpNotifyProcess.h"
00034 #include "ItemFactory.h"
00035 #include "SplitItemProcess.h"
00036 #include "GameMapGump.h"
00037 #include "MainActor.h"
00038 #include "getObject.h"
00039 
00040 #include "IDataSource.h"
00041 #include "ODataSource.h"
00042 
00043 DEFINE_RUNTIME_CLASSTYPE_CODE(ContainerGump,ItemRelativeGump);
00044 
00045 ContainerGump::ContainerGump()
00046         : ItemRelativeGump(), display_dragging(false)
00047 {
00048 
00049 }
00050 
00051 ContainerGump::ContainerGump(Shape* shape_, uint32 framenum_, uint16 owner,
00052                                                          uint32 Flags_, sint32 layer)
00053         : ItemRelativeGump(0, 0, 5, 5, owner, Flags_, layer),
00054           display_dragging(false)
00055 {
00056         shape = shape_;
00057         framenum = framenum_;
00058 }
00059 
00060 ContainerGump::~ContainerGump()
00061 {
00062 
00063 }
00064 
00065 void ContainerGump::InitGump(Gump* newparent, bool take_focus)
00066 {
00067         ShapeFrame* sf = shape->getFrame(framenum);
00068         assert(sf);
00069 
00070         dims.w = sf->width;
00071         dims.h = sf->height;
00072 
00073         // Wait with ItemRelativeGump initialization until we calculated our size.
00074         ItemRelativeGump::InitGump(newparent, take_focus);
00075 
00076         // make every item enter the fast area
00077         Container* c = getContainer(owner);
00078 
00079         if (!c) return; // Container gone!?
00080 
00081         // Position isn't like in the original
00082         // U8 puts a container gump slightly to the left of an object
00083 }
00084 
00085 void ContainerGump::getItemCoords(Item* item, sint32& itemx, sint32& itemy)
00086 {
00087         item->getGumpLocation(itemx,itemy);
00088 
00089         if (itemx == 0xFF && itemy == 0xFF) {
00090                 // randomize position
00091                 // TODO: maybe try to put it somewhere where it doesn't overlap others?
00092 
00093                 itemx = std::rand() % itemarea.w;
00094                 itemy = std::rand() % itemarea.h;
00095 
00096                 item->setGumpLocation(itemx, itemy);
00097         }
00098 
00099         itemx += itemarea.x;
00100         itemy += itemarea.y;
00101 }
00102 
00103 
00104 void ContainerGump::PaintThis(RenderSurface* surf, sint32 lerp_factor, bool scaled)
00105 {
00106         // paint self
00107         ItemRelativeGump::PaintThis(surf, lerp_factor, scaled);
00108 
00109         Container* c = getContainer(owner);
00110 
00111         if (!c) {
00112                 // Container gone!?
00113                 Close();
00114                 return;
00115         }
00116 
00117         std::list<Item*>& contents = c->contents;
00118         sint32 gametick = Kernel::get_instance()->getFrameNum();
00119 
00121         bool paintEditorItems = GUIApp::get_instance()->isPaintEditorItems();
00122 
00123         std::list<Item*>::iterator iter;
00124         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00125                 Item* item = *iter;
00126                 item->setupLerp(gametick);
00127 
00128                 if (!paintEditorItems && item->getShapeInfo()->is_editor())
00129                         continue;
00130 
00131                 sint32 itemx,itemy;
00132                 getItemCoords(item, itemx, itemy);
00133                 Shape* s = item->getShapeObject();
00134                 assert(s);
00135                 surf->Paint(s, item->getFrame(), itemx, itemy);
00136         }
00137 
00138 
00139         if (display_dragging) {
00140                 sint32 itemx, itemy;
00141                 itemx = dragging_x + itemarea.x;
00142                 itemy = dragging_y + itemarea.y;
00143                 Shape* s = GameData::get_instance()->getMainShapes()->
00144                         getShape(dragging_shape);
00145                 assert(s);
00146                 surf->PaintInvisible(s, dragging_frame, itemx, itemy, false, (dragging_flags&Item::FLG_FLIPPED)!=0);
00147         }
00148         
00149 }
00150 
00151 // Find object (if any) at (mx,my)
00152 // (mx,my) are relative to parent
00153 uint16 ContainerGump::TraceObjId(int mx, int my)
00154 {
00155         uint16 objid = Gump::TraceObjId(mx,my);
00156         if (objid && objid != 65535) return objid;
00157 
00158         ParentToGump(mx,my);
00159 
00160         Container* c = getContainer(owner);
00161 
00162         if (!c) return 0; // Container gone!?
00163 
00164         bool paintEditorItems = GUIApp::get_instance()->isPaintEditorItems();
00165 
00166         std::list<Item*>& contents = c->contents;
00167         std::list<Item*>::reverse_iterator iter;
00168         // iterate backwards, since we're painting from begin() to end()
00169         for (iter = contents.rbegin(); iter != contents.rend(); ++iter) {
00170                 Item* item = *iter;
00171                 if (!paintEditorItems && item->getShapeInfo()->is_editor())
00172                         continue;
00173 
00174                 sint32 itemx,itemy;
00175                 getItemCoords(item, itemx, itemy);
00176                 Shape* s = item->getShapeObject();
00177                 assert(s);
00178                 ShapeFrame* frame = s->getFrame(item->getFrame());
00179 
00180                 if (frame->hasPoint(mx - itemx, my - itemy))
00181                 {
00182                         // found it
00183                                 return item->getObjId();
00184                 }
00185         }
00186 
00187         // didn't find anything, so return self
00188         return getObjId();
00189 }
00190 
00191 // get item coords relative to self
00192 bool ContainerGump::GetLocationOfItem(uint16 itemid, int &gx, int &gy,
00193                                                                           sint32 lerp_factor)
00194 {
00195         Item* item = getItem(itemid);
00196         Item* parent = item->getParentAsContainer();
00197         if (!parent) return false;
00198         if (parent->getObjId() != owner) return false;
00199 
00201 
00202         sint32 itemx, itemy;
00203         getItemCoords(item, itemx, itemy);
00204 
00205         gx = itemx;
00206         gy = itemy;
00207 
00208         return false;
00209 }
00210 
00211 // we don't want our position to depend on Gump of parent container
00212 // so change the default ItemRelativeGump behaviour
00213 void ContainerGump::GetItemLocation(sint32 lerp_factor)
00214 {
00215         Item *it = getItem(owner);
00216 
00217         if (!it) {
00218                 // This shouldn't ever happen, the GumpNotifyProcess should
00219                 // close us before we get here
00220                 Close();
00221                 return;
00222         }
00223 
00224         int gx, gy;
00225         Item* topitem = it;
00226 
00227         Container *p = it->getParentAsContainer();
00228         if (p) {
00229                 while (p->getParentAsContainer()) {
00230                         p = p->getParentAsContainer();
00231                 }
00232 
00233                 topitem = p;
00234         }
00235 
00236         Gump *gump = GetRootGump()->FindGump(GameMapGump::ClassType);
00237         assert(gump);
00238         gump->GetLocationOfItem(topitem->getObjId(), gx, gy, lerp_factor);
00239 
00240         // Convert the GumpSpaceCoord relative to the world/item gump
00241         // into screenspace coords
00242         gy = gy-it->getShapeInfo()->z*8-16;
00243         gump->GumpToScreenSpace(gx,gy);
00244 
00245         // Convert the screenspace coords into the coords of us
00246         if (parent) parent->ScreenSpaceToGump(gx,gy);
00247 
00248         // Set x and y, and center us over it
00249         ix = gx-dims.w/2;
00250         iy = gy-dims.h;
00251 }
00252 
00253 void ContainerGump::Close(bool no_del)
00254 {
00255         // close any gumps belonging to contents
00256         // and make every item leave the fast area
00257         Container* c = getContainer(owner);
00258         if (!c) return; // Container gone!?
00259 
00260         std::list<Item*>& contents = c->contents;
00261         std::list<Item*>::iterator iter = contents.begin();
00262         while(iter != contents.end()) {
00263                 Item* item = *iter;
00264                 ++iter;
00265                 Gump* g = getGump(item->getGump());
00266                 if (g) {
00267                         g->Close(); 
00268                 }
00269                 item->leaveFastArea();  // Can destroy the item
00270         }
00271 
00272         Item* o = getItem(owner);
00273         if (o)
00274                 o->clearGump(); 
00275 
00276         ItemRelativeGump::Close(no_del);
00277 }
00278 
00279 Container* ContainerGump::getTargetContainer(Item* item, int mx, int my)
00280 {
00281         int px = mx, py = my;
00282         GumpToParent(px, py);
00283         Container* targetcontainer = getContainer(TraceObjId(px, py));
00284 
00285         if (targetcontainer && targetcontainer->getObjId() == item->getObjId())
00286                 targetcontainer = 0;
00287 
00288         if (targetcontainer) {
00289                 ShapeInfo * targetinfo = targetcontainer->getShapeInfo();
00290                 if ((targetcontainer->getObjId() == item->getObjId()) ||
00291                         targetinfo->is_land() || 
00292                         (targetcontainer->getFlags() & Item::FLG_IN_NPC_LIST))
00293                 {
00294                         targetcontainer = 0;
00295                 }
00296         }
00297 
00298         if (!targetcontainer)
00299                 targetcontainer = getContainer(owner);
00300 
00301         return targetcontainer;
00302 }
00303 
00304 
00305 Gump* ContainerGump::OnMouseDown(int button, int mx, int my)
00306 {
00307         Gump* handled = Gump::OnMouseDown(button, mx, my);
00308         if (handled) return handled;
00309 
00310         // only interested in left clicks
00311         if (button == BUTTON_LEFT)
00312                 return this;
00313 
00314         return 0;
00315 }
00316 
00317 void ContainerGump::OnMouseClick(int button, int mx, int my)
00318 {
00319         if (button == BUTTON_LEFT)
00320         {
00321                 if (GUIApp::get_instance()->isAvatarInStasis()) {
00322                         pout << "Can't: avatarInStasis" << std::endl; 
00323                         return;
00324                 }
00325                 
00326                 uint16 objID = TraceObjId(mx, my);
00327 
00328                 Item *item = getItem(objID);
00329                 if (item) {
00330                         item->dumpInfo();
00331                         
00332                         // call the 'look' event
00333                         item->callUsecodeEvent_look();
00334                 }
00335         }
00336 }
00337 
00338 void ContainerGump::OnMouseDouble(int button, int mx, int my)
00339 {
00340         if (button == BUTTON_LEFT)
00341         {
00342                 if (GUIApp::get_instance()->isAvatarInStasis()) {
00343                         pout << "Can't: avatarInStasis" << std::endl; 
00344                         return;
00345                 }
00346                 
00347                 uint16 objID = TraceObjId(mx, my);
00348 
00349                 if (objID == getObjId()) {
00350                         objID = owner; // use container when double click on self
00351                 }
00352 
00353                 Item *item = getItem(objID);
00354                 if (item) {
00355                         item->dumpInfo();
00356 
00357                         MainActor* avatar = getMainActor();
00358                         if (objID == owner || avatar->canReach(item, 128)) { // CONSTANT!
00359                                 // call the 'use' event
00360                                 item->use();
00361                         } else {
00362                                 GUIApp::get_instance()->flashCrossCursor();
00363                         }                       
00364                 }               
00365         }
00366 }
00367 
00368 
00369 bool ContainerGump::StartDraggingItem(Item* item, int mx, int my)
00370 {
00371         // probably don't need to check if item can be moved, since it shouldn't
00372         // be in a container otherwise
00373 
00374         Container* c = getContainer(owner);
00375         assert(c);
00376 
00377         // check if the container the item is in is in range
00378         MainActor* avatar = getMainActor();
00379         if (!avatar->canReach(c, 128)) return false;
00380 
00381         sint32 itemx,itemy;
00382         getItemCoords(item, itemx, itemy);
00383 
00384         GUIApp::get_instance()->setDraggingOffset(mx - itemx, my - itemy);
00385 
00386         return true;
00387 }
00388 
00389 bool ContainerGump::DraggingItem(Item* item, int mx, int my)
00390 {
00391         Container* c = getContainer(owner);
00392         assert(c);
00393 
00394         // check if the container the item is in is in range
00395         MainActor* avatar = getMainActor();
00396         if (!avatar->canReach(c, 128)) {
00397                 display_dragging = false;
00398                 return false;
00399         }
00400 
00401         int dox, doy;
00402         GUIApp::get_instance()->getDraggingOffset(dox, doy);    
00403         GUIApp::get_instance()->setMouseCursor(GUIApp::MOUSE_TARGET);
00404         display_dragging = true;
00405 
00406         dragging_shape = item->getShape();
00407         dragging_frame = item->getFrame();
00408         dragging_flags = item->getFlags();
00409 
00410         // determine target location and set dragging_x/y
00411 
00412         dragging_x = mx - itemarea.x - dox;
00413         dragging_y = my - itemarea.y - doy;
00414 
00415         if (dragging_x < 0 || dragging_x >= itemarea.w ||
00416                 dragging_y < 0 || dragging_y >= itemarea.h) {
00417                 display_dragging = false;
00418                 return false;
00419         }
00420 
00421         // check if item will fit (weight/volume/adding container to itself)
00422         Container* target = getTargetContainer(item,mx,my);
00423         if (!target || !target->CanAddItem(item, true)) {
00424                 display_dragging = false;
00425                 return false;
00426         }
00427 
00428         return true;
00429 }
00430 
00431 void ContainerGump::DraggingItemLeftGump(Item* item)
00432 {
00433         display_dragging = false;
00434 }
00435 
00436 
00437 void ContainerGump::StopDraggingItem(Item* item, bool moved)
00438 {
00439         if (!moved) return; // nothing to do
00440 }
00441 
00442 void ContainerGump::DropItem(Item* item, int mx, int my)
00443 {
00444         display_dragging = false;
00445 
00446         int px = mx, py = my;
00447         GumpToParent(px, py);
00448         // see what the item is being dropped on
00449         Item* targetitem = getItem(TraceObjId(px, py));
00450         Container* targetcontainer = p_dynamic_cast<Container*>(targetitem);
00451 
00452 
00453         if (item->getShapeInfo()->hasQuantity() &&
00454                 item->getQuality() > 1)
00455         {
00456                 // more than one, so see if we should ask if we should split it up
00457 
00458                 Item* splittarget = 0;
00459 
00460                 // also try to combine
00461                 if (targetitem && item->canMergeWith(targetitem)) {
00462                         splittarget = targetitem;
00463                 }
00464 
00465                 if (!splittarget) {
00466                         // create new item
00467                         splittarget = ItemFactory::createItem(
00468                                 item->getShape(), item->getFrame(), 0,
00469                                 item->getFlags() & (Item::FLG_DISPOSABLE | Item::FLG_OWNED | Item::FLG_INVISIBLE | Item::FLG_FLIPPED | Item::FLG_FAST_ONLY | Item::FLG_LOW_FRICTION), item->getNpcNum(), item->getMapNum(),
00470                                 item->getExtFlags() & (Item::EXT_SPRITE | Item::EXT_HIGHLIGHT | Item::EXT_TRANSPARENT), true);
00471                         if (!splittarget) {
00472                                 perr << "ContainerGump failed to create item ("
00473                                          << item->getShape() << "," << item->getFrame()
00474                                          << ") while splitting" << std::endl;
00475                                 return;
00476                         }
00477 
00478 
00479                         if (targetcontainer) {
00480                                 splittarget->moveToContainer(targetcontainer);
00481                                 splittarget->randomGumpLocation();
00482                         } else {
00483                                 splittarget->moveToContainer(getContainer(owner));
00484                                 splittarget->setGumpLocation(dragging_x, dragging_y);
00485                         }
00486                 }                       
00487 
00488                 SliderGump* slidergump = new SliderGump(100, 100,
00489                                                                                                 0, item->getQuality(),
00490                                                                                                 item->getQuality());
00491                 slidergump->InitGump(0);
00492                 slidergump->CreateNotifier(); // manually create notifier
00493                 Process* notifier = slidergump->GetNotifyProcess();
00494                 SplitItemProcess* splitproc = new SplitItemProcess(item, splittarget);
00495                 Kernel::get_instance()->addProcess(splitproc);
00496                 splitproc->waitFor(notifier);
00497 
00498                 return;
00499         }
00500 
00501         if (targetitem && item->getShapeInfo()->hasQuantity())
00502         {
00503                 // try to combine items
00504                 if (item->canMergeWith(targetitem))
00505                 {
00506                         targetitem->setQuality(targetitem->getQuality() +
00507                                                                    item->getQuality());
00508                         targetitem->callUsecodeEvent_combine();
00509                         
00510                         // combined, so delete item
00511                         item->destroy(); item = 0;
00512                         return;
00513                 }
00514         }
00515 
00516         targetcontainer = getTargetContainer(item,mx,my);
00517         assert(targetcontainer);
00518 
00519         if (targetcontainer->getObjId() != owner) {
00520                 if (item->getParent() == targetcontainer->getObjId()) {
00521                         // already in this container, so move item to let it be drawn
00522                         // on top of all other items
00523                         targetcontainer->moveItemToEnd(item);
00524                 } else {
00525                         item->moveToContainer(targetcontainer);
00526                         item->randomGumpLocation();
00527                 }
00528         } else {
00529                 // add item to self
00530 
00531                 if (item->getParent() == owner) {
00532                         targetcontainer->moveItemToEnd(item);
00533                 } else {
00534                         item->moveToContainer(targetcontainer);
00535                 }
00536 
00537                 int dox, doy;
00538                 GUIApp::get_instance()->getDraggingOffset(dox, doy);
00539                 dragging_x = mx - itemarea.x - dox;
00540                 dragging_y = my - itemarea.y - doy;
00541                 item->setGumpLocation(dragging_x, dragging_y);
00542         }
00543 }
00544 
00545 void ContainerGump::saveData(ODataSource* ods)
00546 {
00547         ItemRelativeGump::saveData(ods);
00548 
00549         ods->write4(static_cast<uint32>(itemarea.x));
00550         ods->write4(static_cast<uint32>(itemarea.y));
00551         ods->write4(static_cast<uint32>(itemarea.w));
00552         ods->write4(static_cast<uint32>(itemarea.h));
00553 }
00554 
00555 bool ContainerGump::loadData(IDataSource* ids, uint32 version)
00556 {
00557         if (!ItemRelativeGump::loadData(ids, version)) return false;
00558 
00559         sint32 iax = static_cast<sint32>(ids->read4());
00560         sint32 iay = static_cast<sint32>(ids->read4());
00561         sint32 iaw = static_cast<sint32>(ids->read4());
00562         sint32 iah = static_cast<sint32>(ids->read4());
00563         itemarea.Set(iax, iay, iaw, iah);
00564 
00565         return true;
00566 }

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