00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00045
00046
00047 Container_game_object::~Container_game_object
00048 (
00049 )
00050 {
00051 }
00052
00053
00054
00055
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();
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 bool Container_game_object::add
00081 (
00082 Game_object *obj,
00083 bool dont_check,
00084 bool combine
00085
00086 )
00087 {
00088 if (!dont_check)
00089 {
00090 int shnum = get_shapenum();
00091 if (shnum == obj->get_shapenum() ||
00092 shnum == 522 ||
00093 (shnum == 798 && GAME_BG))
00094 return false;
00095 }
00096
00097 if (Game::get_game_type() == SERPENT_ISLE && get_shapenum() == 914) {
00098 return false;
00099 }
00100
00101
00102 Game_object *parent = this;
00103 do
00104 if (obj == parent)
00105 return false;
00106 while ((parent = parent->get_owner()) != 0);
00107
00108 if (combine)
00109 {
00110 Shape_info& info = obj->get_info();
00111 int quant = obj->get_quantity();
00112
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)
00117 {
00118 obj->remove_this();
00119 return true;
00120 }
00121 else if (newquant < quant)
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
00129 if (maxvol > 0 && objvol + volume_used > maxvol)
00130 return false;
00131 }
00132 volume_used += objvol;
00133 obj->set_owner(this);
00134 objects.append(obj);
00135
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
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
00154 volume_used += obj->get_volume() - oldvol;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163 static int Add2keyring
00164 (
00165 int qual,
00166 int framenum
00167 )
00168 {
00169 if (framenum >=21 && framenum <= 23)
00170 return 0;
00171 Keyring *ring =
00172 Game_window::get_instance()->get_usecode()->getKeyring();
00173
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
00184
00185
00186
00187
00188
00189 static bool Get_combine_info
00190 (
00191 int shapenum,
00192 int framenum,
00193 bool& quantity_frame
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)
00202 {
00203 case 644:
00204 case 627:
00205 case 581:
00206 case 554:
00207 case 556:
00208 case 558:
00209 case 560:
00210 case 568:
00211 case 722:
00212 case 723:
00213 case 417:
00214 case 948:
00215 quantity_frame = true;
00216 break;
00217 case 951:
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
00230
00231
00232
00233
00234
00235 int Container_game_object::add_quantity
00236 (
00237 int delta,
00238 int shapenum,
00239 int qual,
00240 int framenum,
00241 int dontcreate
00242 )
00243 {
00244 if (delta <= 0)
00245 return delta;
00246
00247 int cant_add = 0;
00248 int maxweight = get_max_weight();
00249 if (maxweight)
00250 {
00251 maxweight *= 10;
00252 int avail = maxweight - get_outermost()->get_weight();
00253 int objweight = Ireg_game_object::get_weight(shapenum, delta);
00254 if (objweight && objweight > avail)
00255 {
00256
00257 int weight1 = (10*objweight)/delta;
00258 cant_add = delta - (10*avail)/(weight1 ? weight1 : 1);
00259 if (cant_add >= delta)
00260 return delta;
00261 delta -= cant_add;
00262 }
00263 }
00264 bool has_quantity_frame;
00265 bool has_quantity = Get_combine_info(
00266 shapenum, framenum, has_quantity_frame);
00267
00268
00269 Game_object *obj;
00270 if (!objects.is_empty())
00271 {
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
00281 else if (GAME_SI && shapenum == 641 &&
00282 obj->get_shapenum() == 485 && delta == 1)
00283 delta -= Add2keyring(qual, framenum);
00284 }
00285 next.reset();
00286 while ((obj = next.get_next()) != 0)
00287 delta = obj->add_quantity(
00288 delta, shapenum, qual, framenum, 1);
00289 }
00290 if (!delta || dontcreate)
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
00299
00300
00301
00302
00303
00304 int Container_game_object::create_quantity
00305 (
00306 int delta,
00307 int shnum,
00308 int qual,
00309 int frnum,
00310 bool temporary
00311 )
00312 {
00313
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())
00318 qual = c_any_qual;
00319 while (delta)
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
00330 if (temporary) newobj->set_flag (Obj_flags::is_temporary);
00331
00332 if (qual != c_any_qual)
00333 newobj->set_quality(qual);
00334 delta--;
00335 if (delta > 0)
00336 delta = newobj->modify_quantity(delta);
00337 }
00338 if (!delta)
00339 return (0);
00340
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
00352
00353
00354
00355
00356
00357 int Container_game_object::remove_quantity
00358 (
00359 int delta,
00360 int shapenum,
00361 int qual,
00362 int framenum
00363 )
00364 {
00365 if (objects.is_empty())
00366 return delta;
00367 Game_object *obj = objects.get_first();
00368 Game_object *last = obj->get_prev();
00369 Game_object *next;
00370 while (obj && delta)
00371 {
00372
00373 next = obj == last ? 0 : obj->get_next();
00374 bool del = false;
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)
00382
00383 delta = obj->remove_quantity(delta, shapenum,
00384 qual, framenum);
00385 obj = next;
00386 }
00387 return (delta);
00388 }
00389
00390
00391
00392
00393
00394
00395
00396 Game_object *Container_game_object::find_item
00397 (
00398 int shapenum,
00399 int qual,
00400 int framenum
00401 )
00402 {
00403 if (objects.is_empty())
00404 return 0;
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
00416 Game_object *found = obj->find_item(shapenum, qual, framenum);
00417 if (found)
00418 return (found);
00419 }
00420 return (0);
00421 }
00422
00423
00424
00425
00426
00427 void Container_game_object::activate
00428 (
00429 int event
00430 )
00431 {
00432 if (edit())
00433 return;
00434 int shnum = get_shapenum();
00435 Gump_manager *gump_man = gumpman;
00436
00437 if (Game::get_game_type() == BLACK_GATE) switch(shnum)
00438 {
00439 case 405:
00440 gump_man->add_gump(this, game->get_shape("gumps/shipshold"));
00441 return;
00442
00443 case 406:
00444 case 407:
00445 case 283:
00446 case 203:
00447 case 416:
00448 case 679:
00449 gump_man->add_gump(this, game->get_shape("gumps/drawer"));
00450 return;
00451
00452 case 400:
00453 case 414:
00454 case 762:
00455 case 778:
00456 case 892:
00457 case 507:
00458 gump_man->add_gump(this, game->get_shape("gumps/body"));
00459 return;
00460
00461 case 800:
00462 gump_man->add_gump(this, game->get_shape("gumps/chest"));
00463 return;
00464
00465 case 801:
00466 gump_man->add_gump(this, game->get_shape("gumps/backpack"));
00467 return;
00468
00469 case 799:
00470 gump_man->add_gump(this, game->get_shape("gumps/box"));
00471 return;
00472
00473 case 802:
00474 gump_man->add_gump(this, game->get_shape("gumps/bag"));
00475 return;
00476
00477 case 803:
00478 gump_man->add_gump(this, game->get_shape("gumps/basket"));
00479 return;
00480
00481 case 804:
00482 gump_man->add_gump(this, game->get_shape("gumps/crate"));
00483 return;
00484
00485 case 819:
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)
00490 {
00491 case 405:
00492 gump_man->add_gump(this, game->get_shape("gumps/shipshold"));
00493 return;
00494
00495 case 406:
00496 case 407:
00497 case 283:
00498 case 416:
00499 case 679:
00500 gump_man->add_gump(this, game->get_shape("gumps/drawer"));
00501 return;
00502
00503 case 400:
00504 case 402:
00505 case 414:
00506 case 762:
00507 case 778:
00508 case 892:
00509 case 507:
00510 gump_man->add_gump(this, game->get_shape("gumps/body"));
00511 return;
00512
00513 case 800:
00514 if (get_quality() >= 251)
00515 {
00516 ucmachine->call_usecode(shnum, this,
00517 (Usecode_machine::Usecode_events) event);
00518 return;
00519 }
00520
00521 case 486:
00522 gump_man->add_gump(this, game->get_shape("gumps/chest"));
00523 return;
00524
00525 case 801:
00526 gump_man->add_gump(this, game->get_shape("gumps/backpack"));
00527 return;
00528
00529 case 799:
00530 gump_man->add_gump(this, game->get_shape("gumps/box"));
00531 return;
00532
00533 case 802:
00534 gump_man->add_gump(this, game->get_shape("gumps/bag"));
00535 return;
00536
00537 case 803:
00538 gump_man->add_gump(this, game->get_shape("gumps/basket"));
00539 return;
00540
00541 case 804:
00542 gump_man->add_gump(this, game->get_shape("gumps/crate"));
00543 return;
00544
00545 case 819:
00546 gump_man->add_gump(this, game->get_shape("gumps/barrel"));
00547 return;
00548
00549 case 297:
00550 gump_man->add_gump(this, game->get_shape("gumps/tree"));
00551 return;
00552
00553 case 555:
00554 gump_man->add_gump(this, game->get_shape("gumps/jawbone"));
00555 return;
00556 }
00557
00558
00559 ucmachine->call_usecode(shnum, this,
00560 (Usecode_machine::Usecode_events) event);
00561 }
00562
00563
00564
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
00581
00582
00583
00584
00585 int Container_game_object::drop
00586 (
00587 Game_object *obj
00588 )
00589 {
00590 if (!get_owner())
00591 return (0);
00592 return (add(obj, false, true));
00593 }
00594
00595
00596
00597
00598
00599 int Container_game_object::count_objects
00600 (
00601 int shapenum,
00602 int qual,
00603 int framenum
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
00613 (framenum == c_any_framenum || (obj->get_framenum()&31) == framenum) &&
00614 (qual == c_any_qual || obj->get_quality() == qual))
00615 {
00616 int quant = obj->get_quantity();
00617 total += quant;
00618 }
00619
00620 total += obj->count_objects(shapenum, qual, framenum);
00621 }
00622 return (total);
00623 }
00624
00625
00626
00627
00628
00629 int Container_game_object::get_objects
00630 (
00631 Game_object_vector& vec,
00632 int shapenum,
00633 int qual,
00634 int framenum
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
00645 (framenum == c_any_framenum || (obj->get_framenum()&31) == framenum))
00646 vec.push_back(obj);
00647
00648 obj->get_objects(vec, shapenum, qual, framenum);
00649 }
00650 return (vec.size() - vecsize);
00651 }
00652
00653
00654
00655
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
00672
00673
00674 void Container_game_object::write_ireg
00675 (
00676 DataSource *out
00677 )
00678 {
00679 unsigned char buf[13];
00680 buf[0] = 12;
00681 uint8 *ptr = &buf[1];
00682 write_common_ireg(ptr);
00683 ptr += 4;
00684 Game_object *first = objects.get_first();
00685 unsigned short tword = first ? first->get_prev()->get_shapenum()
00686 : 0;
00687 Write2(ptr, tword);
00688 *ptr++ = 0;
00689 *ptr++ = get_quality();
00690 int npc = get_live_npc_num();
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;
00698 *ptr++ = (get_lift()&15)<<4;
00699 *ptr++ = (unsigned char)resistance;
00700
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);
00705
00706 Game_map::write_scheduled(out, this);
00707 }
00708
00709
00710 int Container_game_object::get_ireg_size()
00711 {
00712
00713 if (gumpman->find_gump(this) || Usecode_script::find(this))
00714 return -1;
00715
00716 int total_size = 13;
00717
00718
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
00738
00739
00740 void Container_game_object::write_contents
00741 (
00742 DataSource *out
00743 )
00744 {
00745 if (!objects.is_empty())
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);
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);
00771 } else {
00772 obj->set_invalid();
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();
00795 obj->remove_this(0);
00796 }
00797 }
00798
00799 void Container_game_object::remove_this(int nodel)
00800 {
00801
00802 if (Container_game_object::get_owner())
00803 {
00804 Ireg_game_object::remove_this(1);
00805 if (nodel)
00806 return;
00807 }
00808 if (!nodel)
00809 extract_contents();
00810
00811 Ireg_game_object::remove_this(nodel);
00812 }