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.360 by root, Wed Nov 16 23:41:59 2016 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 (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * 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 5 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992 Frank Tore Johansen 6 * Copyright (©) 1992 Frank Tore Johansen
7 * 7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under 8 * 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 9 * 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 10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version. 11 * option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 16 * GNU General Public License for more details.
17 * 17 *
18 * You should have received a copy of the Affero GNU General Public License 18 * 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 19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>. 20 * <http://www.gnu.org/licenses/>.
21 * 21 *
22 * The authors can be reached via e-mail to <support@deliantra.net> 22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */ 23 */
24 24
25#include <global.h> 25#include <global.h>
26#include <stdio.h> 26#include <stdio.h>
71 9, 10, 13, 14, 17, 18, 21, 22, 71 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, 72 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 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}; 74};
75 75
76const char *wall_suffix[16] = {
77 "0",
78 "1_3",
79 "1_4",
80 "2_1_2",
81 "1_2",
82 "2_2_4",
83 "2_2_1",
84 "3_1",
85 "1_1",
86 "2_2_3",
87 "2_2_2",
88 "3_3",
89 "2_1_1",
90 "3_4",
91 "3_2",
92 "4"
93};
94
76static void 95static void
77write_uuid (uval64 skip, bool sync) 96write_uuid (uval64 skip, bool sync)
78{ 97{
79 CALL_BEGIN (2); 98 CALL_BEGIN (2);
80 CALL_ARG_SV (newSVval64 (skip)); 99 CALL_ARG_SV (newSVval64 (skip));
214 233
215/* Returns TRUE if every key_values in wants has a partner with the same value in has. */ 234/* Returns TRUE if every key_values in wants has a partner with the same value in has. */
216static bool 235static bool
217compare_ob_value_lists_one (const object *wants, const object *has) 236compare_ob_value_lists_one (const object *wants, const object *has)
218{ 237{
219 /* n-squared behaviour (see kv_get), but I'm hoping both 238 /* 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 239 * objects with lists are rare, and lists stay short. If not, use a
221 * different structure or at least keep the lists sorted... 240 * different structure or at least keep the lists sorted...
222 */ 241 */
223 242
224 /* For each field in wants, */ 243 /* For each field in wants, */
225 for (key_value *kv = wants->key_values; kv; kv = kv->next) 244 for (key_value *kv = wants->kv.first; kv; kv = kv->next)
226 if (has->kv_get (kv->key) != kv->value) 245 if (has->kv.get (kv->key) != kv->value)
227 return false; 246 return false;
228 247
229 /* If we get here, every field in wants has a matching field in has. */ 248 /* If we get here, every field in wants has a matching field in has. */
230 return true; 249 return true;
231} 250}
255 */ 274 */
256bool object::can_merge_slow (object *ob1, object *ob2) 275bool object::can_merge_slow (object *ob1, object *ob2)
257{ 276{
258 /* A couple quick sanity checks */ 277 /* A couple quick sanity checks */
259 if (ob1 == ob2 278 if (ob1 == ob2
260 || ob1->type != ob2->type 279 || ob1->type != ob2->type
261 || ob1->value != ob2->value 280 || ob1->value != ob2->value
262 || ob1->name != ob2->name 281 || ob1->name != ob2->name
282 || ob1->custom_name != ob2->custom_name
263 || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED) 283 || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED)
264 return 0; 284 return 0;
265 285
266 /* Do not merge objects if nrof would overflow, assume nrof 286 /* Do not merge objects if nrof would overflow, assume nrof
267 * is always 0 .. 2**31-1 */ 287 * is always 0 .. 2**31-1 */
331 /* inventory ok - still need to check rest of this object to see 351 /* inventory ok - still need to check rest of this object to see
332 * if it is valid. 352 * if it is valid.
333 */ 353 */
334 } 354 }
335 355
336 /* Don't merge objects that are applied. With the new 'body' code, 356 /* 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 357 * 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. 358 * some items equipped, and we don't want those to merge.
339 */ 359 */
340 if (ob1->flag [FLAG_APPLIED] || ob2->flag [FLAG_APPLIED]) 360 if (ob1->flag [FLAG_APPLIED] || ob2->flag [FLAG_APPLIED])
341 return 0; 361 return 0;
342 362
343 /* Note sure why the following is the case - either the object has to 363 /* 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 364 * be animated or have a very low speed. Is this an attempted monster
345 * check? 365 * check?
346 */ 366 */
347 if (!ob1->flag [FLAG_ANIMATE] && ob1->has_active_speed ()) 367 if (!ob1->flag [FLAG_ANIMATE] && ob1->has_active_speed ())
348 return 0; 368 return 0;
349 369
353 if (ob1->level != ob2->level) 373 if (ob1->level != ob2->level)
354 return 0; 374 return 0;
355 break; 375 break;
356 } 376 }
357 377
358 if (ob1->key_values || ob2->key_values) 378 if (!ob1->kv.empty () || !ob2->kv.empty ())
359 { 379 {
360 /* At least one of these has key_values. */ 380 /* At least one of these has key_values. */
361 if ((!ob1->key_values) != (!ob2->key_values)) 381 if (ob1->kv.empty () != ob2->kv.empty ())
362 return 0; /* One has fields, but the other one doesn't. */ 382 return 0; /* One has fields, but the other one doesn't. */
363 383
364 if (!compare_ob_value_lists (ob1, ob2)) 384 if (!compare_ob_value_lists (ob1, ob2))
365 return 0; 385 return 0;
366 } 386 }
426 446
427 return 0; 447 return 0;
428} 448}
429 449
430// adjust weight per container type ("of holding") 450// adjust weight per container type ("of holding")
431static sint32 451static weight_t
432weight_adjust_for (object *op, sint32 weight) 452weight_adjust_for (object *op, weight_t weight)
433{ 453{
434 return op->type == CONTAINER 454 if (op->type == CONTAINER)
435 ? lerp (weight, 0, 100, 0, 100 - op->stats.Str) 455 weight -= weight * op->stats.Str / 100;
436 : weight;
437}
438 456
457 return weight;
458}
459
439/* 460/*
440 * adjust_weight(object, weight) adds the specified weight to an object, 461 * subtracts, then adds, the specified weight to an object,
441 * and also updates how much the environment(s) is/are carrying. 462 * and also updates how much the environment(s) is/are carrying.
442 */ 463 */
443static void 464static void
444adjust_weight (object *op, sint32 weight) 465adjust_weight (object *op, weight_t sub, weight_t add)
445{ 466{
446 while (op) 467 while (op)
447 { 468 {
448 // adjust by actual difference to account for rounding errors 469 weight_t carrying = (weight_t)op->carrying
449 // i.e. (w2 - w1) / f != w2 / f - w1 / f and the latter is correct 470 - weight_adjust_for (op, sub)
450 weight = weight_adjust_for (op, op->carrying) 471 + weight_adjust_for (op, add);
451 - weight_adjust_for (op, op->carrying - weight);
452 472
453 if (!weight) 473 sub = op->carrying;
454 return;
455
456 op->carrying += weight; 474 op->carrying = carrying;
475 add = op->carrying;
457 476
458 if (object *pl = op->visible_to ()) 477 if (object *pl = op->visible_to ())
459 if (pl != op) // player is handled lazily 478 if (pl != op) // player is handled lazily
460 esrv_update_item (UPD_WEIGHT, pl, op); 479 esrv_update_item (UPD_WEIGHT, pl, op);
461 480
469 * containers are carrying, and sums it up. 488 * containers are carrying, and sums it up.
470 */ 489 */
471void 490void
472object::update_weight () 491object::update_weight ()
473{ 492{
474 sint32 sum = 0; 493 weight_t sum = 0;
475 494
476 for (object *op = inv; op; op = op->below) 495 for (object *op = inv; op; op = op->below)
477 { 496 {
478 if (op->inv)
479 op->update_weight (); 497 op->update_weight ();
480 498
481 sum += op->total_weight (); 499 sum += weight_adjust_for (this, op->total_weight ());
482 } 500 }
483
484 sum = weight_adjust_for (this, sum);
485 501
486 if (sum != carrying) 502 if (sum != carrying)
487 { 503 {
488 if (carrying != sum)//D 504 if (carrying != sum && carrying)//D
489 LOG (llevDebug, "updating weight got %ld, expected %ld (%s)\n", 505 LOG (llevDebug, "updating carrying got %ld, expected %ld (%s)\n",
490 (long long)sum, (long long)carrying, debug_desc ()); 506 (long long)sum, (long long)carrying, debug_desc ());
491 507
492 carrying = sum; 508 carrying = sum;
493 509
494 if (object *pl = visible_to ()) 510 if (object *pl = visible_to ())
582 LOG (llevError | logBacktrace, "tried to set owner of %s to %s\n", debug_desc (), owner->debug_desc ()); 598 LOG (llevError | logBacktrace, "tried to set owner of %s to %s\n", debug_desc (), owner->debug_desc ());
583 return; 599 return;
584 } 600 }
585 601
586 this->owner = owner; 602 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} 603}
605 604
606/* 605/*
607 * copy_to first frees everything allocated by the dst object, 606 * copy_to first frees everything allocated by the dst object,
608 * and then copies the contents of itself into the second 607 * and then copies the contents of itself into the second
614void 613void
615object::copy_to (object *dst) 614object::copy_to (object *dst)
616{ 615{
617 dst->remove (); 616 dst->remove ();
618 *(object_copy *)dst = *this; 617 *(object_copy *)dst = *this;
618
619 // maybe move to object_copy?
620 dst->kv = kv;
621
619 dst->flag [FLAG_REMOVED] = true; 622 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 (); 623 dst->activate ();
650} 624}
651 625
652void 626void
653object::instantiate () 627object::instantiate ()
654{ 628{
655 if (!uuid.seq) // HACK 629 if (!uuid.seq) // HACK
656 uuid = UUID::gen (); 630 uuid = UUID::gen ();
657 631
658 // TODO: unclean state changes, should nt be done in copy_to AND instantiate 632 // TODO: unclean state changes, should not be done in copy_to AND instantiate
659 if (flag [FLAG_RANDOM_SPEED] && speed) 633 if (flag [FLAG_RANDOM_SPEED] && speed)
660 speed_left = - speed - rndm (); // TODO animation 634 speed_left = - speed - rndm (); // TODO animation
661 else 635 else
662 speed_left = -1.; 636 speed_left = -1.;
663 637
664 /* copy the body_info to the body_used - this is only really 638 /* 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. 639 * 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 640 * by doing so, when a monster is created, it has good starting
667 * values for the body_used info, so when items are created 641 * values for the body_used info, so when items are created
668 * for it, they can be properly equipped. 642 * for it, they can be properly equipped.
669 */ 643 */
670 for (int i = NUM_BODY_LOCATIONS; i--; ) 644 for (int i = NUM_BODY_LOCATIONS; i--; )
671 slot[i].used = slot[i].info; 645 slot[i].used = slot[i].info;
672 646
764 } 738 }
765 739
766 mapspace &m = op->ms (); 740 mapspace &m = op->ms ();
767 741
768 if (!(m.flags_ & P_UPTODATE)) 742 if (!(m.flags_ & P_UPTODATE))
769 /* nop */; 743 m.update_up (); // nothing to do except copy up
770 else if (action == UP_OBJ_INSERT) 744 else if (action == UP_OBJ_INSERT)
771 { 745 {
772#if 0 746#if 0
773 // this is likely overkill, TODO: revisit (schmorp) 747 // this is likely overkill, TODO: revisit (schmorp)
774 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW)) 748 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW))
795 * that is being removed. 769 * that is being removed.
796 */ 770 */
797 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) 771 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
798 m.invalidate (); 772 m.invalidate ();
799 else if (action == UP_OBJ_FACE) 773 else if (action == UP_OBJ_FACE)
800 /* Nothing to do for that case */ ; 774 m.update_up (); // nothing to do for that case, except copy up
801 else 775 else
802 LOG (llevError, "update_object called with invalid action: %d\n", action); 776 LOG (llevError, "update_object called with invalid action: %d\n", action);
803 777
804 if (op->more) 778 if (op->more)
805 update_object (op->more, action); 779 update_object (op->more, action);
816 790
817object::~object () 791object::~object ()
818{ 792{
819 unlink (); 793 unlink ();
820 794
821 free_key_values (this); 795 kv.clear ();
822} 796}
823 797
824void object::link () 798void object::link ()
825{ 799{
826 assert (!index);//D 800 assert (!index);//D
925 * if some form of movement is allowed, let objects 899 * if some form of movement is allowed, let objects
926 * drop on that space. 900 * drop on that space.
927 */ 901 */
928 if (!drop_to_ground 902 if (!drop_to_ground
929 || !map 903 || !map
930 || map->in_memory != MAP_ACTIVE 904 || !map->linkable ()
931 || map->no_drop 905 || map->no_drop
932 || ms ().move_block == MOVE_ALL) 906 || ms ().move_block == MOVE_ALL)
933 { 907 {
934 while (inv) 908 while (inv)
935 inv->destroy (); 909 inv->destroy ();
1032 1006
1033 freelist = li; 1007 freelist = li;
1034 ++free_count; 1008 ++free_count;
1035} 1009}
1036 1010
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 1011void
1057object::do_destroy () 1012object::do_destroy ()
1058{ 1013{
1059 if (flag [FLAG_IS_LINKED]) 1014 if (flag [FLAG_IS_LINKED])
1060 remove_link (); 1015 remove_link ();
1144 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed 1099 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed
1145 if (object *pl = visible_to ()) 1100 if (object *pl = visible_to ())
1146 esrv_del_item (pl->contr, count); 1101 esrv_del_item (pl->contr, count);
1147 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed 1102 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed
1148 1103
1149 adjust_weight (env, -total_weight ()); 1104 adjust_weight (env, total_weight (), 0);
1150 1105
1151 object *pl = in_player (); 1106 object *pl = in_player ();
1152 1107
1153 /* we set up values so that it could be inserted into 1108 /* we set up values so that it could be inserted into
1154 * the map, but we don't actually do that - it is up 1109 * the map, but we don't actually do that - it is up
1168 1123
1169 if (pl && pl->is_player ()) 1124 if (pl && pl->is_player ())
1170 { 1125 {
1171 if (expect_false (pl->contr->combat_ob == this)) 1126 if (expect_false (pl->contr->combat_ob == this))
1172 { 1127 {
1173 pl->apply (pl->contr->combat_ob, AP_UNAPPLY); 1128 pl->apply (pl->contr->combat_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1174 pl->contr->combat_ob = 0; 1129 pl->contr->combat_ob = 0;
1175 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob); 1130 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob);
1176 } 1131 }
1177 1132
1178 if (expect_false (pl->contr->ranged_ob == this)) 1133 if (expect_false (pl->contr->ranged_ob == this))
1179 { 1134 {
1180 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY); 1135 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1181 pl->contr->ranged_ob = 0; 1136 pl->contr->ranged_ob = 0;
1182 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob); 1137 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob);
1183 } 1138 }
1184 1139
1185 pl->contr->queue_stats_update (); 1140 pl->contr->queue_stats_update ();
1225 1180
1226 above = 0; 1181 above = 0;
1227 below = 0; 1182 below = 0;
1228 1183
1229 ms.invalidate (); 1184 ms.invalidate ();
1230
1231 if (map->in_memory == MAP_SAVING)
1232 return;
1233 1185
1234 int check_walk_off = !flag [FLAG_NO_APPLY]; 1186 int check_walk_off = !flag [FLAG_NO_APPLY];
1235 1187
1236 if (object *pl = ms.player ()) 1188 if (object *pl = ms.player ())
1237 { 1189 {
1372{ 1324{
1373 op->remove (); 1325 op->remove ();
1374 1326
1375 if (m == &freed_map)//D TODO: remove soon 1327 if (m == &freed_map)//D TODO: remove soon
1376 {//D 1328 {//D
1377 LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D 1329 LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
1378 }//D 1330 }//D
1379 1331
1380 /* Ideally, the caller figures this out. However, it complicates a lot 1332 /* 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 1333 * of areas of callers (eg, anything that uses find_free_spot would now
1382 * need extra work 1334 * need extra work
1572 */ 1524 */
1573 1525
1574 /* if this is not the head or flag has been passed, don't check walk on status */ 1526 /* 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 ()) 1527 if (!(flag & INS_NO_WALK_ON) && op->is_head ())
1576 { 1528 {
1577 if (check_move_on (op, originator)) 1529 if (check_move_on (op, originator, flag))
1578 return 0; 1530 return 0;
1579 1531
1580 /* If we are a multi part object, lets work our way through the check 1532 /* If we are a multi part object, let's work our way through the check
1581 * walk on's. 1533 * walk on's.
1582 */ 1534 */
1583 for (object *tmp = op->more; tmp; tmp = tmp->more) 1535 for (object *tmp = op->more; tmp; tmp = tmp->more)
1584 if (check_move_on (tmp, originator)) 1536 if (check_move_on (tmp, originator, flag))
1585 return 0; 1537 return 0;
1586 } 1538 }
1587 1539
1588 return op; 1540 return op;
1589} 1541}
1629 if (!items // testing !items ensures we can drop at least one item 1581 if (!items // testing !items ensures we can drop at least one item
1630 || (items < m->max_items 1582 || (items < m->max_items
1631 && ms.volume () < m->max_volume)) 1583 && ms.volume () < m->max_volume))
1632 return true; 1584 return true;
1633 1585
1634 if (originator && originator->is_player ()) 1586 if (originator)
1635 originator->contr->failmsgf ( 1587 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.>", 1588 "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 () 1589 query_name ()
1638 ); 1590 );
1639 1591
1640 return false; 1592 return false;
1641} 1593}
1655 1607
1656 nr = min (nr, nrof); 1608 nr = min (nr, nrof);
1657 1609
1658 if (nrof > nr) 1610 if (nrof > nr)
1659 { 1611 {
1612 weight_t oweight = total_weight ();
1613
1660 nrof -= nr; 1614 nrof -= nr;
1661 adjust_weight (env, -weight * max (1, nr)); // carrying == 0
1662 1615
1663 if (object *pl = visible_to ()) 1616 if (object *pl = visible_to ())
1664 esrv_update_item (UPD_NROF, pl, this); 1617 esrv_update_item (UPD_NROF, pl, this);
1618
1619 adjust_weight (env, oweight, total_weight ());
1665 1620
1666 return true; 1621 return true;
1667 } 1622 }
1668 else 1623 else
1669 { 1624 {
1744 if (op->nrof) 1699 if (op->nrof)
1745 for (object *tmp = inv; tmp; tmp = tmp->below) 1700 for (object *tmp = inv; tmp; tmp = tmp->below)
1746 if (object::can_merge (tmp, op)) 1701 if (object::can_merge (tmp, op))
1747 { 1702 {
1748 /* return the original object and remove inserted object 1703 /* return the original object and remove inserted object
1749 (client needs the original object) */ 1704 (client prefers the original object) */
1705
1706 // carrying must be 0 for mergable objects
1707 weight_t oweight = weight_t (tmp->weight) * tmp->nrof;
1708
1750 tmp->nrof += op->nrof; 1709 tmp->nrof += op->nrof;
1751 1710
1752 if (object *pl = tmp->visible_to ()) 1711 if (object *pl = tmp->visible_to ())
1753 esrv_update_item (UPD_NROF, pl, tmp); 1712 esrv_update_item (UPD_NROF, pl, tmp);
1754 1713
1755 adjust_weight (this, op->total_weight ()); 1714 adjust_weight (this, oweight, weight_t (tmp->weight) * tmp->nrof);
1756 1715
1757 op->destroy (); 1716 op->destroy ();
1758 op = tmp; 1717 op = tmp;
1759 goto inserted; 1718 goto inserted;
1760 } 1719 }
1776 op->flag [FLAG_REMOVED] = 0; 1735 op->flag [FLAG_REMOVED] = 0;
1777 1736
1778 if (object *pl = op->visible_to ()) 1737 if (object *pl = op->visible_to ())
1779 esrv_send_item (pl, op); 1738 esrv_send_item (pl, op);
1780 1739
1781 adjust_weight (this, op->total_weight ()); 1740 adjust_weight (this, 0, op->total_weight ());
1782 1741
1783inserted: 1742inserted:
1784 /* reset the light list and los of the players on the map */ 1743 /* reset the light list and los of the players on the map */
1785 if (op->glow_radius && is_on_map ()) 1744 if (op->glow_radius && is_on_map ())
1786 { 1745 {
1815 * MSW 2001-07-08: Check all objects on space, not just those below 1774 * 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 1775 * object being inserted. insert_ob_in_map may not put new objects
1817 * on top. 1776 * on top.
1818 */ 1777 */
1819int 1778int
1820check_move_on (object *op, object *originator) 1779check_move_on (object *op, object *originator, int flags)
1821{ 1780{
1822 if (op->flag [FLAG_NO_APPLY]) 1781 if (op->flag [FLAG_NO_APPLY])
1823 return 0; 1782 return 0;
1824 1783
1825 object *tmp; 1784 object *tmp;
1884 1843
1885 /* Basically same logic as above, except now for actual apply. */ 1844 /* Basically same logic as above, except now for actual apply. */
1886 if ((!op->move_type && tmp->move_on & MOVE_WALK) || 1845 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)) 1846 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1888 { 1847 {
1848 if ((flags & INS_NO_AUTO_EXIT)
1849 && (tmp->type == EXIT || tmp->type == TELEPORTER
1850 || tmp->type == HOLE || tmp->type == TRAPDOOR)) //TODO: temporary, fix exits instead
1851 continue;
1852
1889 move_apply (tmp, op, originator); 1853 move_apply (tmp, op, originator);
1890 1854
1891 if (op->destroyed ()) 1855 if (op->destroyed ())
1892 return 1; 1856 return 1;
1893 1857
2045 */ 2009 */
2046int 2010int
2047find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop) 2011find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop)
2048{ 2012{
2049 int altern[SIZEOFFREE]; 2013 int altern[SIZEOFFREE];
2050 int index = 0, flag; 2014 int index = 0;
2051 2015
2052 for (int i = start; i < stop; i++) 2016 for (int i = start; i < stop; i++)
2053 { 2017 {
2054 mapxy pos (m, x, y); pos.move (i); 2018 mapxy pos (m, x, y); pos.move (i);
2055 2019
2167 * there is capable of. 2131 * there is capable of.
2168 */ 2132 */
2169int 2133int
2170find_dir (maptile *m, int x, int y, object *exclude) 2134find_dir (maptile *m, int x, int y, object *exclude)
2171{ 2135{
2172 int max = SIZEOFFREE, mflags; 2136 int max = SIZEOFFREE;
2173 MoveType move_type; 2137 MoveType move_type;
2174 2138
2175 if (exclude && exclude->head_ () != exclude) 2139 if (exclude && exclude->head_ () != exclude)
2176 { 2140 {
2177 exclude = exclude->head; 2141 exclude = exclude->head;
2230#if 1 // new algorithm 2194#if 1 // new algorithm
2231 // this works by putting x, y into 16 sectors, which 2195 // this works by putting x, y into 16 sectors, which
2232 // are not equal sized, but are a better approximation 2196 // are not equal sized, but are a better approximation
2233 // then the old algorithm, and then using a mapping 2197 // then the old algorithm, and then using a mapping
2234 // table to map it into a direction value. 2198 // table to map it into a direction value.
2199 // basically, it maps these comparisons to each bit
2200 // bit #3: x < 0
2201 // bit #2: y < 0
2202 // bit #1: x > y
2203 // bit #0: x > 2y
2235 2204
2236 static const uint8 dir[16] = { 2205 static const uint8 dir[16] = {
2237 4, 5, 4, 3, 2206 4, 5, 4, 3,
2238 2, 1, 2, 3, 2207 2, 1, 2, 3,
2239 6, 5, 6, 7, 2208 6, 5, 6, 7,
2423 return /*who->flag [FLAG_WIZ]|| */ 2392 return /*who->flag [FLAG_WIZ]|| */
2424 (item->weight > 0 && !item->flag [FLAG_NO_PICK] && 2393 (item->weight > 0 && !item->flag [FLAG_NO_PICK] &&
2425 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3)); 2394 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3));
2426} 2395}
2427 2396
2397//-GPL
2398
2428/* 2399/*
2429 * create clone from object to another 2400 * create clone from object to another
2430 */ 2401 */
2431object * 2402object *
2432object::deep_clone () 2403object::deep_clone ()
2462 return tmp; 2433 return tmp;
2463 2434
2464 return 0; 2435 return 0;
2465} 2436}
2466 2437
2438/* Zero the key_values on op, decrementing the shared-string
2439 * refcounts and freeing the links.
2440 */
2441void
2442key_values::clear ()
2443{
2444 for (key_value *kvp = first; kvp; )
2445 {
2446 key_value *next = kvp->next;
2447 delete kvp;
2448 kvp = next;
2449 }
2450
2451 first = 0;
2452}
2453
2467shstr_tmp 2454shstr_tmp
2468object::kv_get (shstr_tmp key) const 2455key_values::get (shstr_tmp key) const
2469{ 2456{
2470 for (key_value *kv = key_values; kv; kv = kv->next) 2457 for (key_value *kv = first; kv; kv = kv->next)
2471 if (kv->key == key) 2458 if (kv->key == key)
2472 return kv->value; 2459 return kv->value;
2473 2460
2474 return shstr (); 2461 return shstr ();
2475} 2462}
2476 2463
2477void 2464void
2465key_values::add (shstr_tmp key, shstr_tmp value)
2466{
2467 key_value *kv = new key_value;
2468
2469 kv->next = first;
2470 kv->key = key;
2471 kv->value = value;
2472
2473 first = kv;
2474}
2475
2476void
2478object::kv_set (shstr_tmp key, shstr_tmp value) 2477key_values::set (shstr_tmp key, shstr_tmp value)
2479{ 2478{
2480 for (key_value *kv = key_values; kv; kv = kv->next) 2479 for (key_value *kv = first; kv; kv = kv->next)
2481 if (kv->key == key) 2480 if (kv->key == key)
2482 { 2481 {
2483 kv->value = value; 2482 kv->value = value;
2484 return; 2483 return;
2485 } 2484 }
2486 2485
2487 key_value *kv = new key_value; 2486 add (key, value);
2488
2489 kv->next = key_values;
2490 kv->key = key;
2491 kv->value = value;
2492
2493 key_values = kv;
2494} 2487}
2495 2488
2496void 2489void
2497object::kv_del (shstr_tmp key) 2490key_values::del (shstr_tmp key)
2498{ 2491{
2499 for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) 2492 for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
2500 if ((*kvp)->key == key) 2493 if ((*kvp)->key == key)
2501 { 2494 {
2502 key_value *kv = *kvp; 2495 key_value *kv = *kvp;
2503 *kvp = (*kvp)->next; 2496 *kvp = (*kvp)->next;
2504 delete kv; 2497 delete kv;
2505 return; 2498 return;
2506 } 2499 }
2500}
2501
2502void
2503key_values::reverse ()
2504{
2505 key_value *prev = 0;
2506 key_value *head = first;
2507
2508 while (head)
2509 {
2510 key_value *node = head;
2511 head = head->next;
2512 node->next = prev;
2513 prev = node;
2514 }
2515
2516 first = prev;
2517}
2518
2519key_values &
2520key_values::operator =(const key_values &kv)
2521{
2522 clear ();
2523
2524 for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
2525 add (kvp->key, kvp->value);
2526
2527 reverse ();
2507} 2528}
2508 2529
2509object::depth_iterator::depth_iterator (object *container) 2530object::depth_iterator::depth_iterator (object *container)
2510: iterator_base (container) 2531: iterator_base (container)
2511{ 2532{
2594object::region () const 2615object::region () const
2595{ 2616{
2596 return map ? map->region (x, y) 2617 return map ? map->region (x, y)
2597 : region::default_region (); 2618 : region::default_region ();
2598} 2619}
2620
2621//+GPL
2599 2622
2600void 2623void
2601object::open_container (object *new_container) 2624object::open_container (object *new_container)
2602{ 2625{
2603 if (container == new_container) 2626 if (container == new_container)
2661 } 2684 }
2662// else if (!old_container->env && contr && contr->ns) 2685// else if (!old_container->env && contr && contr->ns)
2663// contr->ns->floorbox_reset (); 2686// contr->ns->floorbox_reset ();
2664} 2687}
2665 2688
2689//-GPL
2690
2691// prefetch some flat area around the player
2692static void
2693prefetch_surrounding_area (object *op, maptile *map, int range)
2694{
2695 for (maprect *rect = map->split_to_tiles (mapwalk_buf,
2696 op->x - range , op->y - range ,
2697 op->x + range + 1, op->y + range + 1);
2698 rect->m;
2699 ++rect)
2700 {
2701 rect->m->touch ();
2702 rect->m->activate ();
2703 }
2704}
2705
2706// prefetch a generous area around the player, also up and down
2707void
2708object::prefetch_surrounding_maps ()
2709{
2710 prefetch_surrounding_area (this, map, 40);
2711
2712 if (maptile *m = map->tile_available (TILE_DOWN))
2713 prefetch_surrounding_area (this, m, 20);
2714
2715 if (maptile *m = map->tile_available (TILE_UP))
2716 prefetch_surrounding_area (this, m, 20);
2717}
2718
2719//+GPL
2720
2666object * 2721object *
2667object::force_find (shstr_tmp name) 2722object::force_find (shstr_tmp name)
2668{ 2723{
2669 /* cycle through his inventory to look for the MARK we want to 2724 /* cycle through his inventory to look for the MARK we want to
2670 * place 2725 * place
2674 return splay (tmp); 2729 return splay (tmp);
2675 2730
2676 return 0; 2731 return 0;
2677} 2732}
2678 2733
2679//-GPL
2680
2681void 2734void
2682object::force_set_timer (int duration) 2735object::force_set_timer (int duration)
2683{ 2736{
2684 this->duration = 1; 2737 this->duration = 1;
2685 this->speed_left = -1.f; 2738 this->speed_left = -1.f;
2691object::force_add (shstr_tmp name, int duration) 2744object::force_add (shstr_tmp name, int duration)
2692{ 2745{
2693 if (object *force = force_find (name)) 2746 if (object *force = force_find (name))
2694 force->destroy (); 2747 force->destroy ();
2695 2748
2696 object *force = get_archetype (FORCE_NAME); 2749 object *force = archetype::get (FORCE_NAME);
2697 2750
2698 force->slaying = name; 2751 force->slaying = name;
2699 force->force_set_timer (duration); 2752 force->force_set_timer (duration);
2700 force->flag [FLAG_APPLIED] = true; 2753 force->flag [FLAG_APPLIED] = true;
2701 2754
2785 return contr->mark; 2838 return contr->mark;
2786 else 2839 else
2787 return 0; 2840 return 0;
2788} 2841}
2789 2842
2843// put marked object first in the inventory
2844// this is used by identify-like spells so players can influence
2845// the order a bit.
2846void
2847object::splay_marked ()
2848{
2849 if (object *marked = mark ())
2850 splay (marked);
2851}
2852

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines