ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
(Generate patch)

Comparing deliantra/server/common/object.C (file contents):
Revision 1.330 by root, Sun Apr 18 14:01:33 2010 UTC vs.
Revision 1.368 by root, Wed Dec 5 19:03:26 2018 UTC

1/* 1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
4 * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team 6 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992 Frank Tore Johansen 7 * Copyright (©) 1992 Frank Tore Johansen
7 * 8 *
8 * Deliantra is free software: you can redistribute it and/or modify it under 9 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the 10 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your 11 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version. 12 * option) any later version.
12 * 13 *
13 * This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 17 * GNU General Public License for more details.
17 * 18 *
18 * You should have received a copy of the Affero GNU General Public License 19 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see 20 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>. 21 * <http://www.gnu.org/licenses/>.
21 * 22 *
22 * The authors can be reached via e-mail to <support@deliantra.net> 23 * The authors can be reached via e-mail to <support@deliantra.net>
23 */ 24 */
24 25
25#include <global.h> 26#include <global.h>
26#include <stdio.h> 27#include <stdio.h>
45uint32_t object::create_count; 46uint32_t object::create_count;
46uint32_t object::destroy_count; 47uint32_t object::destroy_count;
47 48
48//+GPL 49//+GPL
49 50
50short freearr_x[SIZEOFFREE] = { 51int freearr_x[SIZEOFFREE] = {
51 0, 52 0,
52 0, 1, 1, 1, 0, -1, -1, -1, 53 0, 1, 1, 1, 0, -1, -1, -1,
53 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1, 54 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
54 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1 55 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
55}; 56};
56short freearr_y[SIZEOFFREE] = { 57int freearr_y[SIZEOFFREE] = {
57 0, 58 0,
58 -1, -1, 0, 1, 1, 1, 0, -1, 59 -1, -1, 0, 1, 1, 1, 0, -1,
59 -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, 60 -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2,
60 -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3 61 -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
61}; 62};
71 9, 10, 13, 14, 17, 18, 21, 22, 72 9, 10, 13, 14, 17, 18, 21, 22,
72 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45, 48, 73 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45, 48,
73 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49 74 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49
74}; 75};
75 76
77const char *wall_suffix[16] = {
78 "0",
79 "1_3",
80 "1_4",
81 "2_1_2",
82 "1_2",
83 "2_2_4",
84 "2_2_1",
85 "3_1",
86 "1_1",
87 "2_2_3",
88 "2_2_2",
89 "3_3",
90 "2_1_1",
91 "3_4",
92 "3_2",
93 "4"
94};
95
76static void 96static void
77write_uuid (uval64 skip, bool sync) 97write_uuid (uval64 skip, bool sync)
78{ 98{
79 CALL_BEGIN (2); 99 CALL_BEGIN (2);
80 CALL_ARG_SV (newSVval64 (skip)); 100 CALL_ARG_SV (newSVval64 (skip));
129{ 149{
130 UUID uid; 150 UUID uid;
131 151
132 uid.seq = ++cur.seq; 152 uid.seq = ++cur.seq;
133 153
134 if (expect_false (cur.seq >= seq_next_save)) 154 if (ecb_expect_false (cur.seq >= seq_next_save))
135 { 155 {
136 seq_next_save = UUID::cur.seq + (UUID_GAP >> 1); 156 seq_next_save = UUID::cur.seq + (UUID_GAP >> 1);
137 write_uuid (UUID_GAP, false); 157 write_uuid (UUID_GAP, false);
138 } 158 }
139 159
214 234
215/* Returns TRUE if every key_values in wants has a partner with the same value in has. */ 235/* Returns TRUE if every key_values in wants has a partner with the same value in has. */
216static bool 236static bool
217compare_ob_value_lists_one (const object *wants, const object *has) 237compare_ob_value_lists_one (const object *wants, const object *has)
218{ 238{
219 /* n-squared behaviour (see kv_get), but I'm hoping both 239 /* n-squared behaviour (see kv.get), but I'm hoping both
220 * objects with lists are rare, and lists stay short. If not, use a 240 * objects with lists are rare, and lists stay short. If not, use a
221 * different structure or at least keep the lists sorted... 241 * different structure or at least keep the lists sorted...
222 */ 242 */
223 243
224 /* For each field in wants, */ 244 /* For each field in wants, */
225 for (key_value *kv = wants->key_values; kv; kv = kv->next) 245 for (key_value *kv = wants->kv.first; kv; kv = kv->next)
226 if (has->kv_get (kv->key) != kv->value) 246 if (has->kv.get (kv->key) != kv->value)
227 return false; 247 return false;
228 248
229 /* If we get here, every field in wants has a matching field in has. */ 249 /* If we get here, every field in wants has a matching field in has. */
230 return true; 250 return true;
231} 251}
255 */ 275 */
256bool object::can_merge_slow (object *ob1, object *ob2) 276bool object::can_merge_slow (object *ob1, object *ob2)
257{ 277{
258 /* A couple quick sanity checks */ 278 /* A couple quick sanity checks */
259 if (ob1 == ob2 279 if (ob1 == ob2
260 || ob1->type != ob2->type 280 || ob1->type != ob2->type
261 || ob1->value != ob2->value 281 || ob1->value != ob2->value
262 || ob1->name != ob2->name 282 || ob1->name != ob2->name
283 || ob1->custom_name != ob2->custom_name
263 || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED) 284 || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED)
264 return 0; 285 return 0;
265 286
266 /* Do not merge objects if nrof would overflow, assume nrof 287 /* Do not merge objects if nrof would overflow, assume nrof
267 * is always 0 .. 2**31-1 */ 288 * is always 0 .. 2**31-1 */
331 /* inventory ok - still need to check rest of this object to see 352 /* inventory ok - still need to check rest of this object to see
332 * if it is valid. 353 * if it is valid.
333 */ 354 */
334 } 355 }
335 356
336 /* Don't merge objects that are applied. With the new 'body' code, 357 /* Don't merge objects that are applied. With the new 'body' code,
337 * it is possible for most any character to have more than one of 358 * it is possible for most any character to have more than one of
338 * some items equipped, and we don't want those to merge. 359 * some items equipped, and we don't want those to merge.
339 */ 360 */
340 if (ob1->flag [FLAG_APPLIED] || ob2->flag [FLAG_APPLIED]) 361 if (ob1->flag [FLAG_APPLIED] || ob2->flag [FLAG_APPLIED])
341 return 0; 362 return 0;
342 363
343 /* Note sure why the following is the case - either the object has to 364 /* Not sure why the following is the case - either the object has to
344 * be animated or have a very low speed. Is this an attempted monster 365 * be animated or have a very low speed. Is this an attempted monster
345 * check? 366 * check?
346 */ 367 */
347 if (!ob1->flag [FLAG_ANIMATE] && ob1->has_active_speed ()) 368 if (!ob1->flag [FLAG_ANIMATE] && ob1->has_active_speed ())
348 return 0; 369 return 0;
349 370
353 if (ob1->level != ob2->level) 374 if (ob1->level != ob2->level)
354 return 0; 375 return 0;
355 break; 376 break;
356 } 377 }
357 378
358 if (ob1->key_values || ob2->key_values) 379 if (!ob1->kv.empty () || !ob2->kv.empty ())
359 { 380 {
360 /* At least one of these has key_values. */ 381 /* At least one of these has key_values. */
361 if ((!ob1->key_values) != (!ob2->key_values)) 382 if (ob1->kv.empty () != ob2->kv.empty ())
362 return 0; /* One has fields, but the other one doesn't. */ 383 return 0; /* One has fields, but the other one doesn't. */
363 384
364 if (!compare_ob_value_lists (ob1, ob2)) 385 if (!compare_ob_value_lists (ob1, ob2))
365 return 0; 386 return 0;
366 } 387 }
426 447
427 return 0; 448 return 0;
428} 449}
429 450
430// adjust weight per container type ("of holding") 451// adjust weight per container type ("of holding")
431static sint32 452static weight_t
432weight_adjust_for (object *op, sint32 weight) 453weight_adjust_for (object *op, weight_t weight)
433{ 454{
434 return op->type == CONTAINER 455 if (op->type == CONTAINER)
435 ? lerp (weight, 0, 100, 0, 100 - op->stats.Str) 456 weight -= weight * op->stats.Str / 100;
436 : weight;
437}
438 457
458 return weight;
459}
460
439/* 461/*
440 * adjust_weight(object, weight) adds the specified weight to an object, 462 * subtracts, then adds, the specified weight to an object,
441 * and also updates how much the environment(s) is/are carrying. 463 * and also updates how much the environment(s) is/are carrying.
442 */ 464 */
443static void 465static void
444adjust_weight (object *op, sint32 weight) 466adjust_weight (object *op, weight_t sub, weight_t add)
445{ 467{
446 while (op) 468 while (op)
447 { 469 {
448 // adjust by actual difference to account for rounding errors 470 weight_t carrying = (weight_t)op->carrying
449 // i.e. (w2 - w1) / f != w2 / f - w1 / f and the latter is correct 471 - weight_adjust_for (op, sub)
450 weight = weight_adjust_for (op, op->carrying) 472 + weight_adjust_for (op, add);
451 - weight_adjust_for (op, op->carrying - weight);
452 473
453 if (!weight) 474 sub = op->carrying;
454 return;
455
456 op->carrying += weight; 475 op->carrying = carrying;
476 add = op->carrying;
457 477
458 if (object *pl = op->visible_to ()) 478 if (object *pl = op->visible_to ())
459 if (pl != op) // player is handled lazily 479 if (pl != op) // player is handled lazily
460 esrv_update_item (UPD_WEIGHT, pl, op); 480 esrv_update_item (UPD_WEIGHT, pl, op);
461 481
469 * containers are carrying, and sums it up. 489 * containers are carrying, and sums it up.
470 */ 490 */
471void 491void
472object::update_weight () 492object::update_weight ()
473{ 493{
474 sint32 sum = 0; 494 weight_t sum = 0;
475 495
476 for (object *op = inv; op; op = op->below) 496 for (object *op = inv; op; op = op->below)
477 { 497 {
478 if (op->inv)
479 op->update_weight (); 498 op->update_weight ();
480 499
481 sum += op->total_weight (); 500 sum += weight_adjust_for (this, op->total_weight ());
482 } 501 }
483
484 sum = weight_adjust_for (this, sum);
485 502
486 if (sum != carrying) 503 if (sum != carrying)
487 { 504 {
488 if (carrying != sum)//D 505 if (carrying != sum && carrying)//D
489 LOG (llevDebug, "updating weight got %ld, expected %ld (%s)\n", 506 LOG (llevDebug, "updating carrying got %ld, expected %ld (%s)\n",
490 (long long)sum, (long long)carrying, debug_desc ()); 507 (long long)sum, (long long)carrying, debug_desc ());
491 508
492 carrying = sum; 509 carrying = sum;
493 510
494 if (object *pl = visible_to ()) 511 if (object *pl = visible_to ())
582 LOG (llevError | logBacktrace, "tried to set owner of %s to %s\n", debug_desc (), owner->debug_desc ()); 599 LOG (llevError | logBacktrace, "tried to set owner of %s to %s\n", debug_desc (), owner->debug_desc ());
583 return; 600 return;
584 } 601 }
585 602
586 this->owner = owner; 603 this->owner = owner;
587}
588
589/* Zero the key_values on op, decrementing the shared-string
590 * refcounts and freeing the links.
591 */
592static void
593free_key_values (object *op)
594{
595 for (key_value *i = op->key_values; i; )
596 {
597 key_value *next = i->next;
598 delete i;
599
600 i = next;
601 }
602
603 op->key_values = 0;
604} 604}
605 605
606/* 606/*
607 * copy_to first frees everything allocated by the dst object, 607 * copy_to first frees everything allocated by the dst object,
608 * and then copies the contents of itself into the second 608 * and then copies the contents of itself into the second
614void 614void
615object::copy_to (object *dst) 615object::copy_to (object *dst)
616{ 616{
617 dst->remove (); 617 dst->remove ();
618 *(object_copy *)dst = *this; 618 *(object_copy *)dst = *this;
619
620 // maybe move to object_copy?
621 dst->kv = kv;
622
619 dst->flag [FLAG_REMOVED] = true; 623 dst->flag [FLAG_REMOVED] = true;
620
621 /* Copy over key_values, if any. */
622 if (key_values)
623 {
624 key_value *tail = 0;
625 dst->key_values = 0;
626
627 for (key_value *i = key_values; i; i = i->next)
628 {
629 key_value *new_link = new key_value;
630
631 new_link->next = 0;
632 new_link->key = i->key;
633 new_link->value = i->value;
634
635 /* Try and be clever here, too. */
636 if (!dst->key_values)
637 {
638 dst->key_values = new_link;
639 tail = new_link;
640 }
641 else
642 {
643 tail->next = new_link;
644 tail = new_link;
645 }
646 }
647 }
648
649 dst->activate (); 624 dst->activate ();
650} 625}
651 626
652void 627void
653object::instantiate () 628object::instantiate ()
654{ 629{
655 if (!uuid.seq) // HACK 630 if (!uuid.seq) // HACK
656 uuid = UUID::gen (); 631 uuid = UUID::gen ();
657 632
658 // TODO: unclean state changes, should nt be done in copy_to AND instantiate 633 // TODO: unclean state changes, should not be done in copy_to AND instantiate
659 if (flag [FLAG_RANDOM_SPEED] && speed) 634 if (flag [FLAG_RANDOM_SPEED] && speed)
660 speed_left = - speed - rndm (); // TODO animation 635 speed_left = - speed - rndm (); // TODO animation
661 else 636 else
662 speed_left = -1.; 637 speed_left = -1.;
663 638
664 /* copy the body_info to the body_used - this is only really 639 /* copy the body_info to the body_used - this is only really
665 * need for monsters, but doesn't hurt to do it for everything. 640 * need for monsters, but doesn't hurt to do it for everything.
666 * by doing so, when a monster is created, it has good starting 641 * by doing so, when a monster is created, it has good starting
667 * values for the body_used info, so when items are created 642 * values for the body_used info, so when items are created
668 * for it, they can be properly equipped. 643 * for it, they can be properly equipped.
669 */ 644 */
670 for (int i = NUM_BODY_LOCATIONS; i--; ) 645 for (int i = 0; i < NUM_BODY_LOCATIONS; ++i)
671 slot[i].used = slot[i].info; 646 slot[i].used = slot[i].info;
672 647
673 attachable::instantiate (); 648 attachable::instantiate ();
674} 649}
675 650
685 660
686 neu->map = map; // not copied by copy_to 661 neu->map = map; // not copied by copy_to
687 return neu; 662 return neu;
688} 663}
689 664
665// update the anhimation frame of an object, but only if it has an animation
666// assigned and the frame number if within the animation.
667void object::update_anim_frame (int frame)
668{
669 if (ecb_expect_false (!has_anim () || frame >= anim_frames ()))
670 return;
671
672 set_anim_frame (frame);
673 update_object (this, UP_OBJ_FACE);
674}
675
690/* 676/*
691 * If an object with the IS_TURNABLE() flag needs to be turned due 677 * If an object with the IS_TURNABLE() flag needs to be turned due
692 * to the closest player being on the other side, this function can 678 * to the closest player being on the other side, this function can
693 * be called to update the face variable, _and_ how it looks on the map. 679 * be called to update the face variable, _and_ how it looks on the map.
694 */ 680 */
696update_turn_face (object *op) 682update_turn_face (object *op)
697{ 683{
698 if (!op->flag [FLAG_IS_TURNABLE] || !op->arch) 684 if (!op->flag [FLAG_IS_TURNABLE] || !op->arch)
699 return; 685 return;
700 686
701 SET_ANIMATION (op, op->direction); 687 op->update_anim_frame (op->direction);
702 update_object (op, UP_OBJ_FACE);
703} 688}
704 689
705/* 690/*
706 * Updates the speed of an object. If the speed changes from 0 to another 691 * Updates the speed of an object. If the speed changes from 0 to another
707 * value, or vice versa, then add/remove the object from the active list. 692 * value, or vice versa, then add/remove the object from the active list.
717 else 702 else
718 deactivate (); 703 deactivate ();
719} 704}
720 705
721/* 706/*
722 * update_object() updates the the map. 707 * update_object() updates the map.
723 * It takes into account invisible objects (and represent squares covered 708 * It takes into account invisible objects (and represent squares covered
724 * by invisible objects by whatever is below them (unless it's another 709 * by invisible objects by whatever is below them (unless it's another
725 * invisible object, etc...) 710 * invisible object, etc...)
726 * If the object being updated is beneath a player, the look-window 711 * If the object being updated is beneath a player, the look-window
727 * of that player is updated (this might be a suboptimal way of 712 * of that player is updated (this might be a suboptimal way of
764 } 749 }
765 750
766 mapspace &m = op->ms (); 751 mapspace &m = op->ms ();
767 752
768 if (!(m.flags_ & P_UPTODATE)) 753 if (!(m.flags_ & P_UPTODATE))
769 /* nop */; 754 m.update_up (); // nothing to do except copy up
770 else if (action == UP_OBJ_INSERT) 755 else if (action == UP_OBJ_INSERT)
771 { 756 {
772#if 0 757#if 0
773 // this is likely overkill, TODO: revisit (schmorp) 758 // this is likely overkill, TODO: revisit (schmorp)
774 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW)) 759 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW))
779 || (op->flag [FLAG_DAMNED] && !(m.flags_ & P_NO_CLERIC)) 764 || (op->flag [FLAG_DAMNED] && !(m.flags_ & P_NO_CLERIC))
780 || (m.move_on | op->move_on ) != m.move_on 765 || (m.move_on | op->move_on ) != m.move_on
781 || (m.move_off | op->move_off ) != m.move_off 766 || (m.move_off | op->move_off ) != m.move_off
782 || (m.move_slow | op->move_slow) != m.move_slow 767 || (m.move_slow | op->move_slow) != m.move_slow
783 /* This isn't perfect, but I don't expect a lot of objects to 768 /* This isn't perfect, but I don't expect a lot of objects to
784 * have move_allow right now. 769 * have move_allow right now.
785 */ 770 */
786 || ((m.move_block | op->move_block) & ~op->move_allow) != m.move_block 771 || ((m.move_block | op->move_block) & ~op->move_allow) != m.move_block
787 m.invalidate (); 772 m.invalidate ();
788#else 773#else
789 // the above is not strong enough a test to skip updating. los maybe? TODO (schmorp) 774 // the above is not strong enough a test to skip updating. los maybe? TODO (schmorp)
795 * that is being removed. 780 * that is being removed.
796 */ 781 */
797 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) 782 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
798 m.invalidate (); 783 m.invalidate ();
799 else if (action == UP_OBJ_FACE) 784 else if (action == UP_OBJ_FACE)
800 /* Nothing to do for that case */ ; 785 m.update_up (); // nothing to do for that case, except copy up
801 else 786 else
802 LOG (llevError, "update_object called with invalid action: %d\n", action); 787 LOG (llevError, "update_object called with invalid action: %d\n", action);
803 788
804 if (op->more) 789 if (op->more)
805 update_object (op->more, action); 790 update_object (op->more, action);
816 801
817object::~object () 802object::~object ()
818{ 803{
819 unlink (); 804 unlink ();
820 805
821 free_key_values (this); 806 kv.clear ();
822} 807}
823 808
824void object::link () 809void object::link ()
825{ 810{
826 assert (!index);//D 811 assert (!index);//D
869 op->activate_recursive (); 854 op->activate_recursive ();
870} 855}
871 856
872/* This function removes object 'op' from the list of active 857/* This function removes object 'op' from the list of active
873 * objects. 858 * objects.
874 * This should only be used for style maps or other such 859 * This should only be used for style maps or other such
875 * reference maps where you don't want an object that isn't 860 * reference maps where you don't want an object that isn't
876 * in play chewing up cpu time getting processed. 861 * in play chewing up cpu time getting processed.
877 * The reverse of this is to call update_ob_speed, which 862 * The reverse of this is to call update_ob_speed, which
878 * will do the right thing based on the speed of the object. 863 * will do the right thing based on the speed of the object.
879 */ 864 */
925 * if some form of movement is allowed, let objects 910 * if some form of movement is allowed, let objects
926 * drop on that space. 911 * drop on that space.
927 */ 912 */
928 if (!drop_to_ground 913 if (!drop_to_ground
929 || !map 914 || !map
930 || map->in_memory != MAP_ACTIVE 915 || !map->linkable ()
931 || map->no_drop 916 || map->no_drop
932 || ms ().move_block == MOVE_ALL) 917 || ms ().move_block == MOVE_ALL)
933 { 918 {
934 while (inv) 919 while (inv)
935 inv->destroy (); 920 inv->destroy ();
1032 1017
1033 freelist = li; 1018 freelist = li;
1034 ++free_count; 1019 ++free_count;
1035} 1020}
1036 1021
1037static struct freed_map : maptile
1038{
1039 freed_map ()
1040 : maptile (3, 3)
1041 {
1042 path = "<freed objects map>";
1043 name = "/internal/freed_objects_map";
1044 no_drop = 1;
1045 no_reset = 1;
1046
1047 in_memory = MAP_ACTIVE;
1048 }
1049
1050 ~freed_map ()
1051 {
1052 destroy ();
1053 }
1054} freed_map; // freed objects are moved here to avoid crashes
1055
1056void 1022void
1057object::do_destroy () 1023object::do_destroy ()
1058{ 1024{
1059 if (flag [FLAG_IS_LINKED]) 1025 if (flag [FLAG_IS_LINKED])
1060 remove_link (); 1026 remove_link ();
1133 flag [FLAG_REMOVED] = true; 1099 flag [FLAG_REMOVED] = true;
1134 1100
1135 if (more) 1101 if (more)
1136 more->remove (); 1102 more->remove ();
1137 1103
1138 /* 1104 /*
1139 * In this case, the object to be removed is in someones 1105 * In this case, the object to be removed is in someones
1140 * inventory. 1106 * inventory.
1141 */ 1107 */
1142 if (env) 1108 if (env)
1143 { 1109 {
1144 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed 1110 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed
1145 if (object *pl = visible_to ()) 1111 if (object *pl = visible_to ())
1146 esrv_del_item (pl->contr, count); 1112 esrv_del_item (pl->contr, count);
1147 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed 1113 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed
1148 1114
1149 adjust_weight (env, -total_weight ()); 1115 adjust_weight (env, total_weight (), 0);
1150 1116
1151 object *pl = in_player (); 1117 object *pl = in_player ();
1152 1118
1153 /* we set up values so that it could be inserted into 1119 /* we set up values so that it could be inserted into
1154 * the map, but we don't actually do that - it is up 1120 * the map, but we don't actually do that - it is up
1166 below = 0; 1132 below = 0;
1167 env = 0; 1133 env = 0;
1168 1134
1169 if (pl && pl->is_player ()) 1135 if (pl && pl->is_player ())
1170 { 1136 {
1171 if (expect_false (pl->contr->combat_ob == this)) 1137 if (ecb_expect_false (pl->contr->combat_ob == this))
1172 { 1138 {
1173 pl->apply (pl->contr->combat_ob, AP_UNAPPLY); 1139 pl->apply (pl->contr->combat_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1174 pl->contr->combat_ob = 0; 1140 pl->contr->combat_ob = 0;
1175 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob); 1141 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob);
1176 } 1142 }
1177 1143
1178 if (expect_false (pl->contr->ranged_ob == this)) 1144 if (ecb_expect_false (pl->contr->ranged_ob == this))
1179 { 1145 {
1180 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY); 1146 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1181 pl->contr->ranged_ob = 0; 1147 pl->contr->ranged_ob = 0;
1182 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob); 1148 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob);
1183 } 1149 }
1184 1150
1185 pl->contr->queue_stats_update (); 1151 pl->contr->queue_stats_update ();
1186 1152
1187 if (expect_false (glow_radius) && pl->is_on_map ()) 1153 if (ecb_expect_false (glow_radius) && pl->is_on_map ())
1188 update_all_los (pl->map, pl->x, pl->y); 1154 update_all_los (pl->map, pl->x, pl->y);
1189 } 1155 }
1190 } 1156 }
1191 else if (map) 1157 else if (map)
1192 { 1158 {
1225 1191
1226 above = 0; 1192 above = 0;
1227 below = 0; 1193 below = 0;
1228 1194
1229 ms.invalidate (); 1195 ms.invalidate ();
1230
1231 if (map->in_memory == MAP_SAVING)
1232 return;
1233 1196
1234 int check_walk_off = !flag [FLAG_NO_APPLY]; 1197 int check_walk_off = !flag [FLAG_NO_APPLY];
1235 1198
1236 if (object *pl = ms.player ()) 1199 if (object *pl = ms.player ())
1237 { 1200 {
1372{ 1335{
1373 op->remove (); 1336 op->remove ();
1374 1337
1375 if (m == &freed_map)//D TODO: remove soon 1338 if (m == &freed_map)//D TODO: remove soon
1376 {//D 1339 {//D
1377 LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D 1340 LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
1378 }//D 1341 }//D
1379 1342
1380 /* Ideally, the caller figures this out. However, it complicates a lot 1343 /* Ideally, the caller figures this out. However, it complicates a lot
1381 * of areas of callers (eg, anything that uses find_free_spot would now 1344 * of areas of callers (eg, anything that uses find_free_spot would now
1382 * need extra work 1345 * need extra work
1451 * We've already dealt with merging if appropriate. 1414 * We've already dealt with merging if appropriate.
1452 * Generally, we want to put the new object on top. But if 1415 * Generally, we want to put the new object on top. But if
1453 * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last 1416 * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
1454 * floor, we want to insert above that and no further. 1417 * floor, we want to insert above that and no further.
1455 * Also, if there are spell objects on this space, we stop processing 1418 * Also, if there are spell objects on this space, we stop processing
1456 * once we get to them. This reduces the need to traverse over all of 1419 * once we get to them. This reduces the need to traverse over all of
1457 * them when adding another one - this saves quite a bit of cpu time 1420 * them when adding another one - this saves quite a bit of cpu time
1458 * when lots of spells are cast in one area. Currently, it is presumed 1421 * when lots of spells are cast in one area. Currently, it is presumed
1459 * that flying non pickable objects are spell objects. 1422 * that flying non pickable objects are spell objects.
1460 */ 1423 */
1461 for (object *tmp = ms.bot; tmp; tmp = tmp->above) 1424 for (object *tmp = ms.bot; tmp; tmp = tmp->above)
1572 */ 1535 */
1573 1536
1574 /* if this is not the head or flag has been passed, don't check walk on status */ 1537 /* if this is not the head or flag has been passed, don't check walk on status */
1575 if (!(flag & INS_NO_WALK_ON) && op->is_head ()) 1538 if (!(flag & INS_NO_WALK_ON) && op->is_head ())
1576 { 1539 {
1577 if (check_move_on (op, originator)) 1540 if (check_move_on (op, originator, flag))
1578 return 0; 1541 return 0;
1579 1542
1580 /* If we are a multi part object, lets work our way through the check 1543 /* If we are a multi part object, let's work our way through the check
1581 * walk on's. 1544 * walk on's.
1582 */ 1545 */
1583 for (object *tmp = op->more; tmp; tmp = tmp->more) 1546 for (object *tmp = op->more; tmp; tmp = tmp->more)
1584 if (check_move_on (tmp, originator)) 1547 if (check_move_on (tmp, originator, flag))
1585 return 0; 1548 return 0;
1586 } 1549 }
1587 1550
1588 return op; 1551 return op;
1589} 1552}
1590 1553
1591/* this function inserts an object in the map, but if it 1554/* this function inserts an object in the map, but if it
1592 * finds an object of its own type, it'll remove that one first. 1555 * finds an object of its own type, it'll remove that one first.
1593 * op is the object to insert it under: supplies x and the map. 1556 * op is the object to insert it under: supplies x and the map.
1594 */ 1557 */
1595void 1558void
1596replace_insert_ob_in_map (shstr_tmp archname, object *op) 1559replace_insert_ob_in_map (shstr_tmp archname, object *op)
1597{ 1560{
1629 if (!items // testing !items ensures we can drop at least one item 1592 if (!items // testing !items ensures we can drop at least one item
1630 || (items < m->max_items 1593 || (items < m->max_items
1631 && ms.volume () < m->max_volume)) 1594 && ms.volume () < m->max_volume))
1632 return true; 1595 return true;
1633 1596
1634 if (originator && originator->is_player ()) 1597 if (originator)
1635 originator->contr->failmsgf ( 1598 originator->failmsgf (
1636 "No matter how hard you try, you just cannot put the %s here H<Try to remove some items from the floor first.>", 1599 "No matter how hard you try, you just cannot put the %s here! H<Try to remove some items from the floor first.>",
1637 query_name () 1600 query_name ()
1638 ); 1601 );
1639 1602
1640 return false; 1603 return false;
1641} 1604}
1655 1618
1656 nr = min (nr, nrof); 1619 nr = min (nr, nrof);
1657 1620
1658 if (nrof > nr) 1621 if (nrof > nr)
1659 { 1622 {
1623 weight_t oweight = total_weight ();
1624
1660 nrof -= nr; 1625 nrof -= nr;
1661 adjust_weight (env, -weight * max (1, nr)); // carrying == 0
1662 1626
1663 if (object *pl = visible_to ()) 1627 if (object *pl = visible_to ())
1664 esrv_update_item (UPD_NROF, pl, this); 1628 esrv_update_item (UPD_NROF, pl, this);
1629
1630 adjust_weight (env, oweight, total_weight ());
1665 1631
1666 return true; 1632 return true;
1667 } 1633 }
1668 else 1634 else
1669 { 1635 {
1723/* 1689/*
1724 * env->insert (op) 1690 * env->insert (op)
1725 * This function inserts the object op in the linked list 1691 * This function inserts the object op in the linked list
1726 * inside the object environment. 1692 * inside the object environment.
1727 * 1693 *
1728 * The function returns now pointer to inserted item, and return value can 1694 * The function returns now pointer to inserted item, and return value can
1729 * be != op, if items are merged. -Tero 1695 * be != op, if items are merged. -Tero
1730 */ 1696 */
1731object * 1697object *
1732object::insert (object *op) 1698object::insert (object *op)
1733{ 1699{
1744 if (op->nrof) 1710 if (op->nrof)
1745 for (object *tmp = inv; tmp; tmp = tmp->below) 1711 for (object *tmp = inv; tmp; tmp = tmp->below)
1746 if (object::can_merge (tmp, op)) 1712 if (object::can_merge (tmp, op))
1747 { 1713 {
1748 /* return the original object and remove inserted object 1714 /* return the original object and remove inserted object
1749 (client needs the original object) */ 1715 (client prefers the original object) */
1716
1717 // carrying must be 0 for mergable objects
1718 weight_t oweight = weight_t (tmp->weight) * tmp->nrof;
1719
1750 tmp->nrof += op->nrof; 1720 tmp->nrof += op->nrof;
1751 1721
1752 if (object *pl = tmp->visible_to ()) 1722 if (object *pl = tmp->visible_to ())
1753 esrv_update_item (UPD_NROF, pl, tmp); 1723 esrv_update_item (UPD_NROF, pl, tmp);
1754 1724
1755 adjust_weight (this, op->total_weight ()); 1725 adjust_weight (this, oweight, weight_t (tmp->weight) * tmp->nrof);
1756 1726
1757 op->destroy (); 1727 op->destroy ();
1758 op = tmp; 1728 op = tmp;
1759 goto inserted; 1729 goto inserted;
1760 } 1730 }
1776 op->flag [FLAG_REMOVED] = 0; 1746 op->flag [FLAG_REMOVED] = 0;
1777 1747
1778 if (object *pl = op->visible_to ()) 1748 if (object *pl = op->visible_to ())
1779 esrv_send_item (pl, op); 1749 esrv_send_item (pl, op);
1780 1750
1781 adjust_weight (this, op->total_weight ()); 1751 adjust_weight (this, 0, op->total_weight ());
1782 1752
1783inserted: 1753inserted:
1784 /* reset the light list and los of the players on the map */ 1754 /* reset the light list and los of the players on the map */
1785 if (op->glow_radius && is_on_map ()) 1755 if (op->glow_radius && is_on_map ())
1786 { 1756 {
1815 * MSW 2001-07-08: Check all objects on space, not just those below 1785 * MSW 2001-07-08: Check all objects on space, not just those below
1816 * object being inserted. insert_ob_in_map may not put new objects 1786 * object being inserted. insert_ob_in_map may not put new objects
1817 * on top. 1787 * on top.
1818 */ 1788 */
1819int 1789int
1820check_move_on (object *op, object *originator) 1790check_move_on (object *op, object *originator, int flags)
1821{ 1791{
1822 if (op->flag [FLAG_NO_APPLY]) 1792 if (op->flag [FLAG_NO_APPLY])
1823 return 0; 1793 return 0;
1824 1794
1825 object *tmp; 1795 object *tmp;
1849 */ 1819 */
1850 if ((op->move_type & ~move_on & ~move_block) != 0 && (op->move_type & ~move_slow & ~move_block) != 0) 1820 if ((op->move_type & ~move_on & ~move_block) != 0 && (op->move_type & ~move_slow & ~move_block) != 0)
1851 return 0; 1821 return 0;
1852 1822
1853 /* The objects have to be checked from top to bottom. 1823 /* The objects have to be checked from top to bottom.
1854 * Hence, we first go to the top: 1824 * Hence, we first go to the top:
1855 */ 1825 */
1856 for (object *next, *tmp = ms.top; tmp; tmp = next) 1826 for (object *next, *tmp = ms.top; tmp; tmp = next)
1857 { 1827 {
1858 next = tmp->below; 1828 next = tmp->below;
1859 1829
1884 1854
1885 /* Basically same logic as above, except now for actual apply. */ 1855 /* Basically same logic as above, except now for actual apply. */
1886 if ((!op->move_type && tmp->move_on & MOVE_WALK) || 1856 if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
1887 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0)) 1857 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1888 { 1858 {
1859 if ((flags & INS_NO_AUTO_EXIT)
1860 && (tmp->type == EXIT || tmp->type == TELEPORTER
1861 || tmp->type == HOLE || tmp->type == TRAPDOOR)) //TODO: temporary, fix exits instead
1862 continue;
1863
1889 move_apply (tmp, op, originator); 1864 move_apply (tmp, op, originator);
1890 1865
1891 if (op->destroyed ()) 1866 if (op->destroyed ())
1892 return 1; 1867 return 1;
1893 1868
2038 * inform the caller. However, insert_ob_in_map will update as 2013 * inform the caller. However, insert_ob_in_map will update as
2039 * necessary, so the caller shouldn't need to do any special work. 2014 * necessary, so the caller shouldn't need to do any special work.
2040 * Note - updated to take an object instead of archetype - this is necessary 2015 * Note - updated to take an object instead of archetype - this is necessary
2041 * because arch_blocked (now ob_blocked) needs to know the movement type 2016 * because arch_blocked (now ob_blocked) needs to know the movement type
2042 * to know if the space in question will block the object. We can't use 2017 * to know if the space in question will block the object. We can't use
2043 * the archetype because that isn't correct if the monster has been 2018 * the archetype because that isn't correct if the monster has been
2044 * customized, changed states, etc. 2019 * customized, changed states, etc.
2045 */ 2020 */
2046int 2021int
2047find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop) 2022find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop)
2048{ 2023{
2049 int altern[SIZEOFFREE]; 2024 int altern[SIZEOFFREE];
2050 int index = 0, flag; 2025 int index = 0;
2051 2026
2052 for (int i = start; i < stop; i++) 2027 for (int i = start; i < stop; i++)
2053 { 2028 {
2054 mapxy pos (m, x, y); pos.move (i); 2029 mapxy pos (m, x, y); pos.move (i);
2055 2030
2071 continue; 2046 continue;
2072 } 2047 }
2073 2048
2074 /* Basically, if we find a wall on a space, we cut down the search size. 2049 /* Basically, if we find a wall on a space, we cut down the search size.
2075 * In this way, we won't return spaces that are on another side of a wall. 2050 * In this way, we won't return spaces that are on another side of a wall.
2076 * This mostly work, but it cuts down the search size in all directions - 2051 * This mostly work, but it cuts down the search size in all directions -
2077 * if the space being examined only has a wall to the north and empty 2052 * if the space being examined only has a wall to the north and empty
2078 * spaces in all the other directions, this will reduce the search space 2053 * spaces in all the other directions, this will reduce the search space
2079 * to only the spaces immediately surrounding the target area, and 2054 * to only the spaces immediately surrounding the target area, and
2080 * won't look 2 spaces south of the target space. 2055 * won't look 2 spaces south of the target space.
2081 */ 2056 */
2111 */ 2086 */
2112int 2087int
2113find_first_free_spot (const object *ob, maptile *m, int x, int y) 2088find_first_free_spot (const object *ob, maptile *m, int x, int y)
2114{ 2089{
2115 for (int i = 0; i < SIZEOFFREE; i++) 2090 for (int i = 0; i < SIZEOFFREE; i++)
2116 if (!ob->blocked (m, x + freearr_x[i], y + freearr_y[i])) 2091 if (!ob->blocked (m, x + DIRX (i), y + DIRY (i)))
2117 return i; 2092 return i;
2118 2093
2119 return -1; 2094 return -1;
2120} 2095}
2121 2096
2132 2107
2133 while (--end) 2108 while (--end)
2134 swap (arr [end], arr [rndm (end + 1)]); 2109 swap (arr [end], arr [rndm (end + 1)]);
2135} 2110}
2136 2111
2137/* new function to make monster searching more efficient, and effective! 2112/* new function to make monster searching more efficient, and effective!
2138 * This basically returns a randomized array (in the passed pointer) of 2113 * This basically returns a randomized array (in the passed pointer) of
2139 * the spaces to find monsters. In this way, it won't always look for 2114 * the spaces to find monsters. In this way, it won't always look for
2140 * monsters to the north first. However, the size of the array passed 2115 * monsters to the north first. However, the size of the array passed
2141 * covers all the spaces, so within that size, all the spaces within 2116 * covers all the spaces, so within that size, all the spaces within
2142 * the 3x3 area will be searched, just not in a predictable order. 2117 * the 3x3 area will be searched, just not in a predictable order.
2167 * there is capable of. 2142 * there is capable of.
2168 */ 2143 */
2169int 2144int
2170find_dir (maptile *m, int x, int y, object *exclude) 2145find_dir (maptile *m, int x, int y, object *exclude)
2171{ 2146{
2172 int max = SIZEOFFREE, mflags; 2147 int max = SIZEOFFREE;
2173 MoveType move_type; 2148 MoveType move_type;
2174 2149
2175 if (exclude && exclude->head_ () != exclude) 2150 if (exclude && exclude->head_ () != exclude)
2176 { 2151 {
2177 exclude = exclude->head; 2152 exclude = exclude->head;
2230#if 1 // new algorithm 2205#if 1 // new algorithm
2231 // this works by putting x, y into 16 sectors, which 2206 // this works by putting x, y into 16 sectors, which
2232 // are not equal sized, but are a better approximation 2207 // are not equal sized, but are a better approximation
2233 // then the old algorithm, and then using a mapping 2208 // then the old algorithm, and then using a mapping
2234 // table to map it into a direction value. 2209 // table to map it into a direction value.
2210 // basically, it maps these comparisons to each bit
2211 // bit #3: x < 0
2212 // bit #2: y < 0
2213 // bit #1: x > y
2214 // bit #0: x > 2y
2235 2215
2236 static const uint8 dir[16] = { 2216 static const uint8 dir[16] = {
2237 4, 5, 4, 3, 2217 4, 5, 4, 3,
2238 2, 1, 2, 3, 2218 2, 1, 2, 3,
2239 6, 5, 6, 7, 2219 6, 5, 6, 7,
2381 int mflags; 2361 int mflags;
2382 2362
2383 if (dir < 0) 2363 if (dir < 0)
2384 return 0; /* exit condition: invalid direction */ 2364 return 0; /* exit condition: invalid direction */
2385 2365
2386 dx = x + freearr_x[dir]; 2366 dx = x + DIRX (dir);
2387 dy = y + freearr_y[dir]; 2367 dy = y + DIRY (dir);
2388 2368
2389 mflags = get_map_flags (m, &m, dx, dy, &dx, &dy); 2369 mflags = get_map_flags (m, &m, dx, dy, &dx, &dy);
2390 2370
2391 /* This functional arguably was incorrect before - it was 2371 /* This functional arguably was incorrect before - it was
2392 * checking for P_WALL - that was basically seeing if 2372 * checking for P_WALL - that was basically seeing if
2423 return /*who->flag [FLAG_WIZ]|| */ 2403 return /*who->flag [FLAG_WIZ]|| */
2424 (item->weight > 0 && !item->flag [FLAG_NO_PICK] && 2404 (item->weight > 0 && !item->flag [FLAG_NO_PICK] &&
2425 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3)); 2405 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3));
2426} 2406}
2427 2407
2408//-GPL
2409
2428/* 2410/*
2429 * create clone from object to another 2411 * create clone from object to another
2430 */ 2412 */
2431object * 2413object *
2432object::deep_clone () 2414object::deep_clone ()
2462 return tmp; 2444 return tmp;
2463 2445
2464 return 0; 2446 return 0;
2465} 2447}
2466 2448
2449/* Zero the key_values on op, decrementing the shared-string
2450 * refcounts and freeing the links.
2451 */
2452void
2453key_values::clear ()
2454{
2455 for (key_value *kvp = first; kvp; )
2456 {
2457 key_value *next = kvp->next;
2458 delete kvp;
2459 kvp = next;
2460 }
2461
2462 first = 0;
2463}
2464
2467shstr_tmp 2465shstr_tmp
2468object::kv_get (shstr_tmp key) const 2466key_values::get (shstr_tmp key) const
2469{ 2467{
2470 for (key_value *kv = key_values; kv; kv = kv->next) 2468 for (key_value *kv = first; kv; kv = kv->next)
2471 if (kv->key == key) 2469 if (kv->key == key)
2472 return kv->value; 2470 return kv->value;
2473 2471
2474 return shstr (); 2472 return shstr ();
2475} 2473}
2476 2474
2477void 2475void
2476key_values::add (shstr_tmp key, shstr_tmp value)
2477{
2478 key_value *kv = new key_value;
2479
2480 kv->next = first;
2481 kv->key = key;
2482 kv->value = value;
2483
2484 first = kv;
2485}
2486
2487void
2478object::kv_set (shstr_tmp key, shstr_tmp value) 2488key_values::set (shstr_tmp key, shstr_tmp value)
2479{ 2489{
2480 for (key_value *kv = key_values; kv; kv = kv->next) 2490 for (key_value *kv = first; kv; kv = kv->next)
2481 if (kv->key == key) 2491 if (kv->key == key)
2482 { 2492 {
2483 kv->value = value; 2493 kv->value = value;
2484 return; 2494 return;
2485 } 2495 }
2486 2496
2487 key_value *kv = new key_value; 2497 add (key, value);
2488
2489 kv->next = key_values;
2490 kv->key = key;
2491 kv->value = value;
2492
2493 key_values = kv;
2494} 2498}
2495 2499
2496void 2500void
2497object::kv_del (shstr_tmp key) 2501key_values::del (shstr_tmp key)
2498{ 2502{
2499 for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) 2503 for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
2500 if ((*kvp)->key == key) 2504 if ((*kvp)->key == key)
2501 { 2505 {
2502 key_value *kv = *kvp; 2506 key_value *kv = *kvp;
2503 *kvp = (*kvp)->next; 2507 *kvp = (*kvp)->next;
2504 delete kv; 2508 delete kv;
2505 return; 2509 return;
2506 } 2510 }
2511}
2512
2513void
2514key_values::reverse ()
2515{
2516 key_value *prev = 0;
2517 key_value *head = first;
2518
2519 while (head)
2520 {
2521 key_value *node = head;
2522 head = head->next;
2523 node->next = prev;
2524 prev = node;
2525 }
2526
2527 first = prev;
2528}
2529
2530key_values &
2531key_values::operator =(const key_values &kv)
2532{
2533 clear ();
2534
2535 for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
2536 add (kvp->key, kvp->value);
2537
2538 reverse ();
2539
2540 return *this;
2507} 2541}
2508 2542
2509object::depth_iterator::depth_iterator (object *container) 2543object::depth_iterator::depth_iterator (object *container)
2510: iterator_base (container) 2544: iterator_base (container)
2511{ 2545{
2594object::region () const 2628object::region () const
2595{ 2629{
2596 return map ? map->region (x, y) 2630 return map ? map->region (x, y)
2597 : region::default_region (); 2631 : region::default_region ();
2598} 2632}
2633
2634//+GPL
2599 2635
2600void 2636void
2601object::open_container (object *new_container) 2637object::open_container (object *new_container)
2602{ 2638{
2603 if (container == new_container) 2639 if (container == new_container)
2661 } 2697 }
2662// else if (!old_container->env && contr && contr->ns) 2698// else if (!old_container->env && contr && contr->ns)
2663// contr->ns->floorbox_reset (); 2699// contr->ns->floorbox_reset ();
2664} 2700}
2665 2701
2702//-GPL
2703
2704// prefetch some flat area around the player
2705static void
2706prefetch_surrounding_area (object *op, maptile *map, int range)
2707{
2708 for (maprect *rect = map->split_to_tiles (mapwalk_buf,
2709 op->x - range , op->y - range ,
2710 op->x + range + 1, op->y + range + 1);
2711 rect->m;
2712 ++rect)
2713 {
2714 rect->m->touch ();
2715 rect->m->activate ();
2716 }
2717}
2718
2719// prefetch a generous area around the player, also up and down
2720void
2721object::prefetch_surrounding_maps ()
2722{
2723 prefetch_surrounding_area (this, map, 40);
2724
2725 if (maptile *m = map->tile_available (TILE_DOWN))
2726 prefetch_surrounding_area (this, m, 20);
2727
2728 if (maptile *m = map->tile_available (TILE_UP))
2729 prefetch_surrounding_area (this, m, 20);
2730}
2731
2732//+GPL
2733
2666object * 2734object *
2667object::force_find (shstr_tmp name) 2735object::force_find (shstr_tmp name)
2668{ 2736{
2669 /* cycle through his inventory to look for the MARK we want to 2737 /* cycle through his inventory to look for the MARK we want to
2670 * place 2738 * place
2671 */ 2739 */
2672 for (object *tmp = inv; tmp; tmp = tmp->below) 2740 for (object *tmp = inv; tmp; tmp = tmp->below)
2673 if (tmp->type == FORCE && tmp->slaying == name) 2741 if (tmp->type == FORCE && tmp->slaying == name)
2674 return splay (tmp); 2742 return splay (tmp);
2675 2743
2676 return 0; 2744 return 0;
2677} 2745}
2678 2746
2679//-GPL
2680
2681void 2747void
2682object::force_set_timer (int duration) 2748object::force_set_timer (int duration)
2683{ 2749{
2684 this->duration = 1; 2750 this->duration = 1;
2685 this->speed_left = -1.f; 2751 this->speed_left = -1.f;
2691object::force_add (shstr_tmp name, int duration) 2757object::force_add (shstr_tmp name, int duration)
2692{ 2758{
2693 if (object *force = force_find (name)) 2759 if (object *force = force_find (name))
2694 force->destroy (); 2760 force->destroy ();
2695 2761
2696 object *force = get_archetype (FORCE_NAME); 2762 object *force = archetype::get (FORCE_NAME);
2697 2763
2698 force->slaying = name; 2764 force->slaying = name;
2699 force->force_set_timer (duration); 2765 force->force_set_timer (duration);
2700 force->flag [FLAG_APPLIED] = true; 2766 force->flag [FLAG_APPLIED] = true;
2701 2767
2785 return contr->mark; 2851 return contr->mark;
2786 else 2852 else
2787 return 0; 2853 return 0;
2788} 2854}
2789 2855
2856// put marked object first in the inventory
2857// this is used by identify-like spells so players can influence
2858// the order a bit.
2859void
2860object::splay_marked ()
2861{
2862 if (object *marked = mark ())
2863 splay (marked);
2864}
2865

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines