Container.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
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 "Container.h"
00022 
00023 #include "ObjectManager.h"
00024 #include "UCMachine.h"
00025 #include "UCList.h"
00026 #include "IDataSource.h"
00027 #include "ODataSource.h"
00028 #include "ItemFactory.h"
00029 #include "MainActor.h"
00030 #include "getObject.h"
00031 #include "CoreApp.h"
00032 
00033 #include "ShapeInfo.h"
00034 
00035 // p_dynamic_cast stuff
00036 DEFINE_RUNTIME_CLASSTYPE_CODE(Container,Item);
00037 
00038 Container::Container()
00039 {
00040 
00041 }
00042 
00043 
00044 Container::~Container()
00045 {
00046         // TODO: handle container's contents.
00047         // Either destroy the contents, or move them up to this container's parent?
00048 
00049 
00050 
00051         // if we don't have an objid, we _must_ delete children
00052         if (objid == 0xFFFF) {
00053                 std::list<Item*>::iterator iter;
00054                 for (iter = contents.begin(); iter != contents.end(); ++iter) {
00055                         delete (*iter);
00056                 }
00057         }
00058 }
00059 
00060 
00061 ObjId Container::assignObjId()
00062 {
00063         ObjId id = Item::assignObjId();
00064 
00065         std::list<Item*>::iterator iter;
00066         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00067                 (*iter)->assignObjId();
00068                 (*iter)->setParent(id);
00069         }
00070 
00071         return id;
00072 }
00073 
00074 void Container::clearObjId()
00075 {
00076         Item::clearObjId();
00077 
00078         std::list<Item*>::iterator iter;
00079         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00080                 (*iter)->clearObjId();
00081         }
00082 }
00083 
00084 
00085 bool Container::CanAddItem(Item* item, bool checkwghtvol)
00086 {
00087         if (!item) return false;
00088         if (item->getParent() == this->getObjId()) return true; // already in here
00089 
00090         Container *c = p_dynamic_cast<Container*>(item);
00091         if (c) {
00092                 // To quote Exult: "Watch for snake eating itself."
00093                 Container* p = this;
00094                 do {
00095                         if (p == c)
00096                                 return false;
00097                 } while ((p = p->getParentAsContainer()) != 0);
00098         }
00099 
00100         if (checkwghtvol) {
00101 
00102                 uint32 volume = getContentVolume();
00103                 uint32 capacity = getCapacity();
00104 
00105                 // Because Avatar should be able to remove backpack and haul a barrel
00106                 // or chest on his back instead, artificially increase backpack volume
00107                 // for chests or barrels.
00108                 uint32 shapeid = item->getShape();
00109                 if(GAME_IS_U8 && (shapeid == 115 /*Barrel*/
00110                    || shapeid == 78 || shapeid == 117 /*Chests*/))
00111                 {
00112                         // TODO: make this off by default, but can enable it through
00113                         // pentagram.ini
00114                         MainActor* avatar = getMainActor();
00115                         ObjId bp = avatar->getEquip(7); // !! constant
00116                         Container* avatarbackpack = getContainer(bp);
00117                         if(avatarbackpack == this)
00118                         {
00119                                 capacity = 500;
00120                         }
00121                 }
00122 
00123                 // FIXME: this check isn't entirely correct. (combining items,...?)
00124                 if (volume + item->getVolume() > capacity)
00125                         return false;
00126 
00127                 Item *p = getTopItem();
00128                 Item *current = item->getTopItem();
00129 
00130                 // From outside to inside Avatar's inventory?
00131                 if (p->getObjId() == 1 && current->getObjId() != 1) {
00132                         MainActor* av = getMainActor();
00133                         unsigned int str = av->getStr();
00134                         // FIXME: this check isn't entirely correct. (combining items,...?)
00135                         //CONSTANT!
00136                         if (p->getTotalWeight() + item->getTotalWeight() > 40 * str)
00137                                 return false;
00138                 }
00139         }
00140 
00141         return true;
00142 }
00143 
00144 bool Container::addItem(Item* item, bool checkwghtvol)
00145 {
00146         if (!CanAddItem(item, checkwghtvol)) return false;
00147         if (item->getParent() == objid) return true; // already in here
00148 
00149         contents.push_back(item);
00150         return true;
00151 }
00152 
00153 
00154 bool Container::removeItem(Item* item)
00155 {
00156         std::list<Item*>::iterator iter;
00157 
00158         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00159                 if (*iter == item) {
00160                         contents.erase(iter);
00161                         return true;
00162                 }
00163         }
00164         return false;
00165 }
00166 
00167 bool Container::moveItemToEnd(Item* item)
00168 {
00169         std::list<Item*>::iterator iter;
00170 
00171         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00172                 if (*iter == item) {
00173                         // found; move to end
00174                         contents.erase(iter);
00175                         contents.push_back(item);
00176                         return true;
00177                 }
00178         }
00179 
00180         // not found
00181 
00182         return false;
00183 }
00184 
00185 void Container::removeContents()
00186 {
00187         // CHECKME: ethereal items?
00188 
00189         Container* parent = getParentAsContainer();
00190         if (parent) {
00191                 // move contents to parent
00192                 while (contents.begin() != contents.end()) {
00193                         Item *item = *(contents.begin());
00194                         item->moveToContainer(parent);
00195                 }
00196         } else {
00197                 // move contents to our coordinates
00198                 while (contents.begin() != contents.end()) {
00199                         Item *item = *(contents.begin());
00200                         item->move(x,y,z);
00201                 }
00202         }
00203 }
00204 
00205 
00206 void Container::destroyContents()
00207 {
00208         while (contents.begin() != contents.end()) {
00209                 Item *item = *(contents.begin());
00210                 Container *cont = p_dynamic_cast<Container*>(item);
00211                 if (cont) cont->destroyContents();
00212                 item->destroy(true); // we destroy the item immediately
00213         }
00214 }
00215 
00216 void Container::setFlagRecursively(uint32 mask)
00217 {
00218         setFlag(mask);
00219 
00220         std::list<Item*>::iterator iter;
00221         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00222                 (*iter)->setFlag(mask);
00223                 Container *cont = p_dynamic_cast<Container*>(*iter);
00224                 if (cont) cont->setFlagRecursively(mask);
00225         }
00226 }
00227 
00228 void Container::destroy(bool delnow)
00229 {
00232 
00233         removeContents();
00234 
00235         Item::destroy(delnow);
00236 }
00237 
00238 uint32 Container::getTotalWeight()
00239 {
00240         uint32 weight = Item::getTotalWeight();
00241 
00242         // CONSTANT!
00243         if (GAME_IS_U8 && getShape() == 79) {
00244                 // contents of keyring don't weigh anything
00245                 return weight;
00246         }
00247 
00248         // CONSTANT!
00249         if (GAME_IS_U8 && getShape() == 115) {
00250                 // barrel weight is unreasonably heavy
00251                 weight = 300;
00252         }
00253 
00254         std::list<Item*>::iterator iter;
00255         
00256         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00257                 weight += (*iter)->getTotalWeight();
00258         }
00259 
00260         return weight;
00261 }
00262 
00263 uint32 Container::getCapacity()
00264 {
00265         uint32 volume = getShapeInfo()->volume;
00266 
00267         return (volume == 0) ? 32 : volume;
00268 }
00269 
00270 uint32 Container::getContentVolume()
00271 {
00272         uint32 volume = 0;
00273 
00274         std::list<Item*>::iterator iter;
00275         
00276         for (iter = contents.begin(); iter != contents.end(); ++iter) { 
00277                 volume += (*iter)->getVolume();
00278         }
00279 
00280         return volume;  
00281 }
00282 
00283 void Container::containerSearch(UCList* itemlist, const uint8* loopscript,
00284                                                                 uint32 scriptsize, bool recurse)
00285 {
00286         std::list<Item*>::iterator iter;
00287         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00288                 // check item against loopscript
00289                 if ((*iter)->checkLoopScript(loopscript, scriptsize)) {
00290                         uint16 objid = (*iter)->getObjId();
00291                         uint8 buf[2];
00292                         buf[0] = static_cast<uint8>(objid);
00293                         buf[1] = static_cast<uint8>(objid >> 8);
00294                         itemlist->append(buf);
00295                 }
00296 
00297                 if (recurse) {
00298                         // recurse into child-containers
00299                         Container *container = p_dynamic_cast<Container*>(*iter);
00300                         if (container)
00301                                 container->containerSearch(itemlist, loopscript,
00302                                                                                    scriptsize, recurse);
00303                 }
00304         }       
00305 }
00306 
00307 void Container::dumpInfo()
00308 {
00309         Item::dumpInfo();
00310 
00311         pout << "Volume: " << getContentVolume() << "/" << getCapacity()
00312                  << ", total weight: " << getTotalWeight() << std::endl;
00313 }
00314 
00315 void Container::saveData(ODataSource* ods)
00316 {
00317         Item::saveData(ods);
00318         ods->write4(contents.size());
00319         std::list<Item*>::iterator iter;
00320         for (iter = contents.begin(); iter != contents.end(); ++iter) {
00321                 (*iter)->save(ods);
00322         }
00323 }
00324 
00325 bool Container::loadData(IDataSource* ids, uint32 version)
00326 {
00327         if (!Item::loadData(ids, version)) return false;
00328 
00329         uint32 contentcount = ids->read4();
00330 
00331         // read contents
00332         for (unsigned int i = 0; i < contentcount; ++i)
00333         {
00334                 Object* obj = ObjectManager::get_instance()->loadObject(ids, version);
00335                 Item* item = p_dynamic_cast<Item*>(obj);
00336                 if (!item) return false;
00337 
00338                 addItem(item);
00339                 item->setParent(objid);
00340         }
00341 
00342         return true;
00343 }
00344 
00345 
00346 uint32 Container::I_removeContents(const uint8* args, unsigned int /*argsize*/)
00347 {
00348         ARG_CONTAINER_FROM_PTR(container);
00349         if (!container) return 0;
00350 
00351         container->removeContents();
00352         return 0;
00353 }
00354 
00355 uint32 Container::I_destroyContents(const uint8* args,unsigned int /*argsize*/)
00356 {
00357         ARG_CONTAINER_FROM_PTR(container);
00358         if (!container) return 0;
00359 
00360         container->destroyContents();
00361         return 0;
00362 }

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