contain.cc

Go to the documentation of this file.
00001 /*
00002  *  contain.cc - Container objects.
00003  *
00004  *  Copyright (C) 1998-1999  Jeffrey S. Freedman
00005  *  Copyright (C) 2000-2001  The Exult Team
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #  include <config.h>
00024 #endif
00025 
00026 #include "contain.h"
00027 #include "gamewin.h"
00028 #include "gamemap.h"
00029 #include "objiter.h"
00030 #include "game.h"
00031 #include "ucmachine.h"
00032 #include "keyring.h"
00033 #include "utils.h"
00034 #include "Gump_manager.h"
00035 #include "databuf.h"
00036 #include "ucsched.h"
00037 
00038 #ifndef UNDER_CE
00039 using std::rand;
00040 using std::ostream;
00041 #endif
00042 
00043 /*
00044  *  Delete all contents.
00045  */
00046 
00047 Container_game_object::~Container_game_object
00048   (
00049   )
00050   {
00051   }
00052 
00053 /*
00054  *  Remove an object.  The object's (cx, cy) fields are set to invalid
00055  *  #'s (255, 255).
00056  */
00057 
00058 void Container_game_object::remove
00059   (
00060   Game_object *obj
00061   )
00062   {
00063   if (objects.is_empty())
00064     return;
00065   volume_used -= obj->get_volume();
00066   obj->set_owner(0);
00067   objects.remove(obj);
00068   obj->set_invalid();   // No longer part of world.
00069   }
00070 
00071 /*
00072  *  Add an object.
00073  *
00074  *  Output: 1, meaning object is completely contained in this.  Obj may
00075  *      be deleted in this case if combine==true.
00076  *    0 if not enough space, although obj's quantity may be
00077  *      reduced if combine==true.
00078  */
00079 
00080 bool Container_game_object::add
00081   (
00082   Game_object *obj,
00083   bool dont_check,    // 1 to skip volume/recursion check.
00084   bool combine      // True to try to combine obj.  MAY
00085           //   cause obj to be deleted.
00086   )
00087   {
00088   if (!dont_check)
00089     {     // Can't put a bag in a bag.
00090     int shnum = get_shapenum();
00091     if (shnum == obj->get_shapenum() ||
00092         shnum == 522 || // Can't put into locked chest.
00093         (shnum == 798 && GAME_BG))  // Or sealed box.
00094     return false;
00095     }
00096   // ugly hack for SI urn (shouldn't be a container)
00097   if (Game::get_game_type() == SERPENT_ISLE && get_shapenum() == 914) {
00098     return false;
00099   }
00100 
00101   // Always check this. ALWAYS!
00102   Game_object *parent = this;
00103   do        // Watch for snake eating itself.
00104     if (obj == parent)
00105       return false;
00106   while ((parent = parent->get_owner()) != 0);
00107 
00108   if (combine)      // Should we try to combine?
00109     {
00110     Shape_info& info = obj->get_info();
00111     int quant = obj->get_quantity();
00112           // Combine, but don't add.
00113     int newquant = add_quantity(quant, obj->get_shapenum(),
00114       info.has_quality() ? obj->get_quality() : c_any_qual,
00115             obj->get_framenum(), true);
00116     if (newquant == 0)  // All added?
00117       {
00118       obj->remove_this();
00119       return true;
00120       }
00121     else if (newquant < quant)  // Partly successful.
00122       obj->modify_quantity(newquant - quant);
00123     }
00124   int objvol = obj->get_volume();
00125   if (!dont_check)
00126     {
00127     int maxvol = get_max_volume();
00128     // maxvol = 0 means infinite (ship's hold, hollow tree, etc...)
00129     if (maxvol > 0 && objvol + volume_used > maxvol)
00130       return false; // Doesn't fit.
00131     }
00132   volume_used += objvol;
00133   obj->set_owner(this);   // Set us as the owner.
00134   objects.append(obj);    // Append to chain.
00135           // Guessing:
00136   if (get_flag(Obj_flags::okay_to_take))
00137     obj->set_flag(Obj_flags::okay_to_take);
00138   return true;
00139   }
00140 
00141 /*
00142  *  Change shape of a member.
00143  */
00144 
00145 void Container_game_object::change_member_shape
00146   (
00147   Game_object *obj,
00148   int newshape
00149   )
00150   {
00151   int oldvol = obj->get_volume();
00152   obj->set_shape(newshape);
00153           // Update total volume.
00154   volume_used += obj->get_volume() - oldvol;
00155   }
00156 
00157 /*
00158  *  Add a key (by quality) to the SI keyring.
00159  *
00160  *  Output: 1 if successful, else 0 (and this does need to be an int).
00161  */
00162 
00163 static int Add2keyring
00164   (
00165   int qual,
00166   int framenum
00167   )
00168   {
00169   if (framenum >=21 && framenum <= 23)
00170     return 0;   // Fire, ice, blackrock in SI.
00171   Keyring *ring = 
00172     Game_window::get_instance()->get_usecode()->getKeyring();
00173           // Valid quality & not already there?
00174   if (qual != c_any_qual && !ring->checkkey(qual))
00175     {
00176     ring->addkey(qual);
00177     return 1;
00178     }
00179   return 0;
00180   }
00181 
00182 /*
00183  *  Get information about whether a shape is a 'quantity' shape, and
00184  *  whether we need to match its framenum to combine it with another.
00185  *
00186  *  Output: True if a 'quantity' shape.
00187  */
00188 
00189 static bool Get_combine_info
00190   (
00191   int shapenum,
00192   int framenum,
00193   bool& quantity_frame    // Rets. true if frame depends on quan.
00194   )
00195   {
00196   Game_window *gwin = Game_window::get_instance();
00197   Shape_info& info = ShapeID::get_info(shapenum);
00198   quantity_frame = false;
00199   if (!info.has_quantity())
00200     return false;
00201   switch (shapenum)   // Which shapes have frames depending
00202     {     //   on their quantity?
00203   case 644:     // Coins.
00204   case 627:     // Lockpicks.
00205   case 581:     // Ammunition.
00206   case 554:     // Burst arrows.
00207   case 556:     // Magic arrows.
00208   case 558:     // Lucky arrows.
00209   case 560:     // Love arrows.
00210   case 568:     // Tseramed arrows.
00211   case 722:     // Arrows.
00212   case 723:     // Bolts.
00213   case 417:     // Magic bolts.
00214   case 948:     // Bolts.  (or SI filari).
00215     quantity_frame = true;
00216     break;
00217   case 951:     // Monetari/guilders:
00218   case 952:
00219     if (GAME_SI)
00220       quantity_frame = true;
00221     break;
00222   default:
00223     break;
00224     }
00225   return true;
00226   }
00227 
00228 /*
00229  *  Recursively add a quantity of an item to those existing in
00230  *  this container, and create new objects if necessary.
00231  *
00232  *  Output: Delta decremented # added.
00233  */
00234 
00235 int Container_game_object::add_quantity
00236   (
00237   int delta,      // Quantity to add.
00238   int shapenum,     // Shape #.
00239   int qual,     // Quality, or c_any_qual for any.
00240   int framenum,     // Frame, or c_any_framenum for any.
00241   int dontcreate      // If 1, don't create new objs.
00242   )
00243 {
00244   if (delta <= 0)
00245     return delta;
00246 
00247   int cant_add = 0;   // # we can't add due to weight.
00248   int maxweight = get_max_weight();// Check weight.
00249   if (maxweight)
00250     { 
00251     maxweight *= 10;  // Work in .1 stones.
00252     int avail = maxweight - get_outermost()->get_weight();
00253     int objweight = Ireg_game_object::get_weight(shapenum, delta);
00254     if (objweight && objweight > avail)
00255       {   // Limit what we can add.
00256           // Work in 1/100ths.
00257       int weight1 = (10*objweight)/delta;
00258       cant_add = delta - (10*avail)/(weight1 ? weight1 : 1);
00259       if (cant_add >= delta)
00260         return delta; // Can't add any.
00261       delta -= cant_add;
00262       }
00263     }
00264   bool has_quantity_frame;  // Quantity-type shape?
00265   bool has_quantity = Get_combine_info(
00266         shapenum, framenum, has_quantity_frame);
00267           // Note:  quantity is ignored for
00268           //   figuring volume.
00269   Game_object *obj;
00270   if (!objects.is_empty())
00271     {     // First try existing items.
00272     Object_iterator next(objects);
00273     while (delta && (obj = next.get_next()) != 0)
00274       {
00275       if (has_quantity && obj->get_shapenum() == shapenum &&
00276            (framenum == c_any_framenum || has_quantity_frame ||
00277           obj->get_framenum() == framenum))
00278 
00279         delta = obj->modify_quantity(delta);
00280           // Adding key to SI keyring?
00281       else if (GAME_SI && shapenum == 641 &&
00282          obj->get_shapenum() == 485 && delta == 1)
00283         delta -= Add2keyring(qual, framenum);
00284       }
00285     next.reset();     // Now try recursively.
00286     while ((obj = next.get_next()) != 0)
00287       delta = obj->add_quantity(
00288           delta, shapenum, qual, framenum, 1);
00289     }
00290   if (!delta || dontcreate) // All added?
00291     return (delta + cant_add);
00292   else
00293     return cant_add + create_quantity(delta, shapenum, qual,
00294         framenum == c_any_framenum ? 0 : framenum);
00295 }
00296 
00297 /*
00298  *  Recursively create a quantity of an item.  Assumes weight check has
00299  *  already been done.
00300  *
00301  *  Output: Delta decremented # added.
00302  */
00303 
00304 int Container_game_object::create_quantity
00305   (
00306   int delta,      // Quantity to add.
00307   int shnum,      // Shape #.
00308   int qual,     // Quality, or c_any_qual for any.
00309   int frnum,      // Frame.
00310   bool temporary      // Create temporary quantity
00311   )
00312   {
00313           // Usecode container?
00314   if (get_shapenum() == 486 && Game::get_game_type() == SERPENT_ISLE)
00315     return delta;
00316   Shape_info& shp_info = ShapeID::get_info(shnum);
00317   if (!shp_info.has_quality())  // Not a quality object?
00318     qual = c_any_qual;  // Then don't set it.
00319   while (delta)     // Create them here first.
00320     {
00321     Game_object *newobj = gmap->create_ireg_object(
00322             shp_info, shnum, frnum,0,0,0);
00323     if (!add(newobj))
00324       {
00325       delete newobj;
00326       break;
00327       }
00328 
00329     // Set temporary
00330     if (temporary) newobj->set_flag (Obj_flags::is_temporary);
00331 
00332     if (qual != c_any_qual) // Set desired quality.
00333       newobj->set_quality(qual);
00334     delta--;
00335     if (delta > 0)
00336       delta =  newobj->modify_quantity(delta);
00337     }
00338   if (!delta)     // All done?
00339     return (0);
00340           // Now try those below.
00341   Game_object *obj;
00342   if (objects.is_empty())
00343     return (delta);
00344   Object_iterator next(objects);
00345   while ((obj = next.get_next()) != 0)
00346     delta = obj->create_quantity(delta, shnum, qual, frnum);
00347   return (delta);
00348   }   
00349 
00350 /*
00351  *  Recursively remove a quantity of an item from those existing in
00352  *  this container.
00353  *
00354  *  Output: Delta decremented by # removed.
00355  */
00356 
00357 int Container_game_object::remove_quantity
00358   (
00359   int delta,      // Quantity to remove.
00360   int shapenum,     // Shape #.
00361   int qual,     // Quality, or c_any_qual for any.
00362   int framenum      // Frame, or c_any_framenum for any.
00363   )
00364   {
00365   if (objects.is_empty())
00366     return delta;   // Empty.
00367   Game_object *obj = objects.get_first();
00368   Game_object *last = obj->get_prev();  // Save last.
00369   Game_object *next;
00370   while (obj && delta)
00371     {
00372           // Might be deleting obj.
00373     next = obj == last ? 0 : obj->get_next();
00374     bool del = false; // Gets 'deleted' flag.
00375     if (obj->get_shapenum() == shapenum &&
00376         (qual == c_any_qual || obj->get_quality() == qual) &&
00377         (framenum == c_any_framenum || 
00378         (obj->get_framenum()&31) == framenum))
00379       delta = -obj->modify_quantity(-delta, &del);
00380 
00381     if (!del)   // Still there?
00382           // Do it recursively.
00383       delta = obj->remove_quantity(delta, shapenum, 
00384               qual, framenum);
00385     obj = next;
00386     }
00387   return (delta);
00388   }
00389 
00390 /*
00391  *  Find and return a desired item.
00392  *
00393  *  Output: ->object if found, else 0.
00394  */
00395 
00396 Game_object *Container_game_object::find_item
00397   (
00398   int shapenum,     // Shape #.
00399   int qual,     // Quality, or c_any_qual for any.
00400   int framenum      // Frame, or c_any_framenum for any.
00401   )
00402   {
00403   if (objects.is_empty())
00404     return 0;   // Empty.
00405   Game_object *obj;
00406   Object_iterator next(objects);
00407   while ((obj = next.get_next()) != 0)
00408     {
00409     if (obj->get_shapenum() == shapenum &&
00410         (framenum == c_any_framenum || 
00411         (obj->get_framenum()&31) == framenum) &&
00412         (qual == c_any_qual || obj->get_quality() == qual))
00413       return (obj);
00414 
00415           // Do it recursively.
00416     Game_object *found = obj->find_item(shapenum, qual, framenum);
00417     if (found)
00418       return (found);
00419     }
00420   return (0);
00421   }
00422 
00423 /*
00424  *  Run usecode when double-clicked.
00425  */
00426 
00427 void Container_game_object::activate
00428   (
00429   int event
00430   )
00431   {
00432   if (edit())
00433     return;     // Map-editing.
00434   int shnum = get_shapenum();
00435   Gump_manager *gump_man = gumpman;
00436 
00437   if (Game::get_game_type() == BLACK_GATE)  switch(shnum) // Watch for gumps.
00438   {
00439     case 405:     // Ship's hold
00440     gump_man->add_gump(this, game->get_shape("gumps/shipshold"));
00441     return;
00442 
00443     case 406:     // Nightstand.
00444     case 407:     // Desk.
00445     case 283:
00446     case 203:
00447     case 416:     // Chest of drawers.
00448     case 679:
00449     gump_man->add_gump(this, game->get_shape("gumps/drawer"));
00450     return;
00451 
00452     case 400:     // Bodies.
00453     case 414:
00454     case 762:
00455     case 778:
00456     case 892:
00457     case 507:       // Bones
00458     gump_man->add_gump(this, game->get_shape("gumps/body"));
00459     return;
00460 
00461     case 800:     // Chest.
00462     gump_man->add_gump(this, game->get_shape("gumps/chest"));
00463     return;
00464 
00465     case 801:     // Backpack.
00466     gump_man->add_gump(this, game->get_shape("gumps/backpack"));
00467     return;
00468 
00469     case 799:     // Unsealed box
00470     gump_man->add_gump(this, game->get_shape("gumps/box"));
00471     return;
00472 
00473     case 802:     // Bag.
00474     gump_man->add_gump(this, game->get_shape("gumps/bag"));
00475     return;
00476 
00477     case 803:     // Basket.
00478     gump_man->add_gump(this, game->get_shape("gumps/basket"));
00479     return;
00480   
00481     case 804:     // Crate.
00482     gump_man->add_gump(this, game->get_shape("gumps/crate"));
00483     return;
00484 
00485     case 819:     // Barrel.
00486     gump_man->add_gump(this, game->get_shape("gumps/barrel"));
00487     return;
00488   }
00489   else if (Game::get_game_type() == SERPENT_ISLE) switch(shnum) // Watch for gumps.
00490   {
00491     case 405:     // Ship's hold
00492     gump_man->add_gump(this, game->get_shape("gumps/shipshold"));
00493     return;
00494 
00495     case 406:     // Nightstand.
00496     case 407:     // Desk.
00497     case 283:
00498     case 416:     // Chest of drawers.
00499     case 679:
00500     gump_man->add_gump(this, game->get_shape("gumps/drawer"));
00501     return;
00502 
00503     case 400:     // Bodies.
00504     case 402:
00505     case 414:
00506     case 762:
00507     case 778:
00508     case 892:
00509     case 507:       // Bones
00510     gump_man->add_gump(this, game->get_shape("gumps/body"));
00511     return;
00512 
00513     case 800:     // Chest.
00514     if (get_quality() >= 251) // Trapped?
00515       {   // Run normal usecode fun.
00516       ucmachine->call_usecode(shnum, this,
00517         (Usecode_machine::Usecode_events) event);
00518       return;
00519       }
00520             // FALL THROUGH to 486.
00521     case 486:     // Usecode container.
00522     gump_man->add_gump(this, game->get_shape("gumps/chest"));
00523     return;
00524 
00525     case 801:     // Backpack.
00526     gump_man->add_gump(this, game->get_shape("gumps/backpack"));
00527     return;
00528 
00529     case 799:     // Unsealed box
00530     gump_man->add_gump(this, game->get_shape("gumps/box"));
00531     return;
00532 
00533     case 802:     // Bag.
00534     gump_man->add_gump(this, game->get_shape("gumps/bag"));
00535     return;
00536 
00537     case 803:     // Basket.
00538     gump_man->add_gump(this, game->get_shape("gumps/basket"));
00539     return;
00540   
00541     case 804:     // Crate.
00542     gump_man->add_gump(this, game->get_shape("gumps/crate"));
00543     return;
00544 
00545     case 819:     // Barrel.
00546     gump_man->add_gump(this, game->get_shape("gumps/barrel"));
00547     return;
00548 
00549     case 297:     // Hollow Tree
00550     gump_man->add_gump(this, game->get_shape("gumps/tree"));
00551     return;
00552 
00553     case 555:     // Serpent Jawbone
00554     gump_man->add_gump(this, game->get_shape("gumps/jawbone"));
00555     return;
00556   }
00557 
00558           // Try to run normal usecode fun.
00559   ucmachine->call_usecode(shnum, this,
00560         (Usecode_machine::Usecode_events) event);
00561   }
00562 
00563 /*
00564  *  Get (total) weight.
00565  */
00566 
00567 int Container_game_object::get_weight
00568   (
00569   )
00570   {
00571   int wt = Ireg_game_object::get_weight();
00572   Game_object *obj;
00573   Object_iterator next(objects);
00574   while ((obj = next.get_next()) != 0)
00575     wt += obj->get_weight();
00576   return wt;
00577   }
00578 
00579 /*
00580  *  Drop another onto this.
00581  *
00582  *  Output: 0 to reject, 1 to accept.
00583  */
00584 
00585 int Container_game_object::drop
00586   (
00587   Game_object *obj    // May be deleted if combined.
00588   )
00589   {
00590   if (!get_owner())   // Only accept if inside another.
00591     return (0);
00592   return (add(obj, false, true)); // We'll take it, and try to combine.
00593   }
00594 
00595 /*
00596  *  Recursively count all objects of a given shape.
00597  */
00598 
00599 int Container_game_object::count_objects
00600   (
00601   int shapenum,     // Shape#, or c_any_shapenum for any.
00602   int qual,     // Quality, or c_any_qual for any.
00603   int framenum      // Frame#, or c_any_framenum for any.
00604   )
00605   {
00606   int total = 0;
00607   Game_object *obj;
00608   Object_iterator next(objects);
00609   while ((obj = next.get_next()) != 0)
00610     {
00611     if ((shapenum == c_any_shapenum || obj->get_shapenum() == shapenum) &&
00612           // Watch for reflection.
00613         (framenum == c_any_framenum || (obj->get_framenum()&31) == framenum) &&
00614         (qual == c_any_qual || obj->get_quality() == qual))
00615       {   // Check quantity.
00616       int quant = obj->get_quantity();
00617       total += quant;
00618       }
00619           // Count recursively.
00620     total += obj->count_objects(shapenum, qual, framenum);
00621     }
00622   return (total);
00623   }
00624 
00625 /*
00626  *  Recursively get all objects of a given shape.
00627  */
00628 
00629 int Container_game_object::get_objects
00630   (
00631   Game_object_vector& vec,  // Objects returned here.
00632   int shapenum,     // Shape#, or c_any_shapenum for any.
00633   int qual,     // Quality, or c_any_qual for any.
00634   int framenum      // Frame#, or c_any_framenum for any.
00635   )
00636   {
00637   int vecsize = vec.size();
00638   Game_object *obj;
00639   Object_iterator next(objects);
00640   while ((obj = next.get_next()) != 0)
00641     {
00642     if ((shapenum == c_any_shapenum || obj->get_shapenum() == shapenum) &&
00643         (qual == c_any_qual || obj->get_quality() == qual) &&
00644           // Watch for reflection.
00645         (framenum == c_any_framenum || (obj->get_framenum()&31) == framenum))
00646       vec.push_back(obj);
00647           // Search recursively.
00648     obj->get_objects(vec, shapenum, qual, framenum);
00649     }
00650   return (vec.size() - vecsize);
00651   }
00652 
00653 
00654 /*
00655  *  Set a flag on this and all contents.
00656  */
00657 
00658 void Container_game_object::set_flag_recursively
00659   (
00660   int flag
00661   )
00662   {
00663   set_flag(flag);
00664   Game_object *obj;
00665   Object_iterator next(objects);
00666   while ((obj = next.get_next()) != 0)
00667     obj->set_flag_recursively(flag);
00668   }
00669 
00670 /*
00671  *  Write out container and its members.
00672  */
00673 
00674 void Container_game_object::write_ireg
00675   (
00676   DataSource *out
00677   )
00678   {
00679   unsigned char buf[13];    // 13-byte entry + length-byte.
00680   buf[0] = 12;
00681   uint8 *ptr = &buf[1]; // To avoid confusion about offsets.
00682   write_common_ireg(ptr);   // Fill in bytes 1-4.
00683   ptr += 4;
00684   Game_object *first = objects.get_first(); // Guessing: +++++
00685   unsigned short tword = first ? first->get_prev()->get_shapenum() 
00686                   : 0;
00687   Write2(ptr, tword);
00688   *ptr++ = 0;     // Unknown.
00689   *ptr++ = get_quality();
00690   int npc = get_live_npc_num(); // If body, get source.
00691   int quant;
00692   if (Game::get_game_type() == SERPENT_ISLE)
00693     quant = npc + 0x80;
00694   else
00695     quant = (npc >= 0 && npc <= 127) ? (npc + 0x80) : 0;
00696 
00697   *ptr++ = quant&0xff;    // "Quantity".
00698   *ptr++ = (get_lift()&15)<<4;  // Lift 
00699   *ptr++ = (unsigned char)resistance;   // Resistance.
00700           // Flags:  B0=invis. B3=okay_to_take.
00701   *ptr++ = get_flag((Obj_flags::invisible) != 0) +
00702      ((get_flag(Obj_flags::okay_to_take) != 0) << 3);
00703   out->write((char*)buf, sizeof(buf));
00704   write_contents(out);    // Write what's contained within.
00705           // Write scheduled usecode.
00706   Game_map::write_scheduled(out, this); 
00707   }
00708 
00709 // Get size of IREG. Returns -1 if can't write to buffer
00710 int Container_game_object::get_ireg_size()
00711 {
00712   // These shouldn't ever happen, but you never know
00713   if (gumpman->find_gump(this) || Usecode_script::find(this))
00714     return -1;
00715 
00716   int total_size = 13;
00717 
00718   // Now what's inside.
00719   if (!objects.is_empty())
00720   {
00721     Game_object *obj;
00722     Object_iterator next(objects);
00723     while ((obj = next.get_next()) != 0) {
00724       int size = obj->get_ireg_size();
00725 
00726       if (size < 0) return -1;
00727 
00728       total_size += size;
00729     }
00730     total_size += 1;
00731   }
00732 
00733   return total_size;
00734 }
00735 
00736 /*
00737  *  Write contents (if there is any).
00738  */
00739 
00740 void Container_game_object::write_contents
00741   (
00742   DataSource *out
00743   )
00744   {
00745   if (!objects.is_empty())  // Now write out what's inside.
00746     {
00747     Game_object *obj;
00748     Object_iterator next(objects);
00749     while ((obj = next.get_next()) != 0)
00750       obj->write_ireg(out);
00751     out->write1(0x01);    // A 01 terminates the list.
00752     }
00753   }
00754 
00755 
00756 bool Container_game_object::extract_contents()
00757 {
00758   if (objects.is_empty())
00759     return true;
00760 
00761   bool status = true;
00762 
00763   Container_game_object *owner = get_owner();
00764   Game_object *obj;
00765 
00766   while ((obj = objects.get_first())) {
00767     remove(obj);
00768 
00769     if (owner) {
00770       owner->add(obj,1); // add without checking volume
00771     } else {
00772       obj->set_invalid(); // set to invalid chunk so move() doesn't fail
00773       if ((get_cx() == 255) && (get_cy() == 255)) {
00774         obj->remove_this(0);
00775         status = false;
00776       } else {
00777         obj->move(get_tile());
00778       }
00779     }
00780   }
00781 
00782   return status;
00783 }
00784 
00785 void Container_game_object::delete_contents()
00786 {
00787   if (objects.is_empty())
00788     return;
00789 
00790   Game_object *obj;
00791   while ((obj = objects.get_first())) {
00792     remove(obj);
00793 
00794     obj->delete_contents(); // recurse into contained containers
00795     obj->remove_this(0);
00796   }
00797 }
00798 
00799 void Container_game_object::remove_this(int nodel)
00800 {
00801           // Special case to avoid recursion.
00802   if (Container_game_object::get_owner())
00803     {     // First remove from owner.
00804     Ireg_game_object::remove_this(1);
00805     if (nodel)    // Not deleting?  Then done.
00806       return;
00807     }
00808   if (!nodel)
00809     extract_contents();
00810 
00811   Ireg_game_object::remove_this(nodel);
00812 }

Generated on Mon Jul 9 14:42:49 2007 for ExultEngine by  doxygen 1.5.1