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.29 by root, Mon Sep 11 12:38:36 2006 UTC vs.
Revision 1.45 by root, Thu Sep 14 18:13:01 2006 UTC

29#include <stdio.h> 29#include <stdio.h>
30#include <sys/types.h> 30#include <sys/types.h>
31#include <sys/uio.h> 31#include <sys/uio.h>
32#include <object.h> 32#include <object.h>
33#include <funcpoint.h> 33#include <funcpoint.h>
34#include <skills.h>
35#include <loader.h> 34#include <loader.h>
36 35
37int nrofallocobjects = 0; 36int nrofallocobjects = 0;
37static UUID uuid;
38const uint64 UUID_SKIP = 1<<19;
38 39
39object *objects; /* Pointer to the list of used objects */
40object *active_objects; /* List of active objects that need to be processed */ 40object *active_objects; /* List of active objects that need to be processed */
41 41
42short freearr_x[SIZEOFFREE] = { 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1, 42short freearr_x[SIZEOFFREE] = { 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
43 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1 43 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
44}; 44};
50}; 50};
51int freedir[SIZEOFFREE] = { 51int freedir[SIZEOFFREE] = {
52 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 52 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8,
53 1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8 53 1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
54}; 54};
55
56static void
57write_uuid (void)
58{
59 char filename1[MAX_BUF], filename2[MAX_BUF];
60
61 sprintf (filename1, "%s/uuid", settings.localdir);
62 sprintf (filename2, "%s/uuid~", settings.localdir);
63
64 FILE *fp;
65
66 if (!(fp = fopen (filename2, "w")))
67 {
68 LOG (llevError, "ERROR: cannot open %s for writing, unable to write UUID!\n", filename2);
69 return;
70 }
71
72 fprintf (fp, "<1,%llx>\n", (unsigned long long)uuid.seq + UUID_SKIP * 2);
73 fclose (fp);
74 rename (filename2, filename1);
75}
76
77static void
78read_uuid (void)
79{
80 char filename[MAX_BUF];
81
82 sprintf (filename, "%s/uuid", settings.localdir);
83
84 FILE *fp;
85
86 if (!(fp = fopen (filename, "r")))
87 {
88 if (errno == ENOENT)
89 {
90 LOG (llevInfo, "RESET uid to 1\n");
91 uuid.seq = 0;
92 write_uuid ();
93 return;
94 }
95
96 LOG (llevError, "FATAL: cannot open %s for reading!\n", filename);
97 _exit (1);
98 }
99
100 int version;
101 unsigned long long uid;
102 if (2 != fscanf (fp, "<%d,%llx>\n", &version, &uid) || version != 1)
103 {
104 LOG (llevError, "FATAL: error reading uid from %s!\n", filename);
105 _exit (1);
106 }
107
108 uuid.seq = uid;
109 write_uuid ();
110 LOG (llevDebug, "read UID: %lld\n", uid);
111 fclose (fp);
112}
113
114UUID
115gen_uuid ()
116{
117 UUID uid;
118
119 uid.seq = ++uuid.seq;
120
121 if (!(uuid.seq & (UUID_SKIP - 1)))
122 write_uuid ();
123
124 return uid;
125}
126
127void
128init_uuid ()
129{
130 read_uuid ();
131}
55 132
56/* Returns TRUE if every key_values in wants has a partner with the same value in has. */ 133/* Returns TRUE if every key_values in wants has a partner with the same value in has. */
57static int 134static int
58compare_ob_value_lists_one (const object *wants, const object *has) 135compare_ob_value_lists_one (const object *wants, const object *has)
59{ 136{
255 { 332 {
256 if (inv->inv) 333 if (inv->inv)
257 sum_weight (inv); 334 sum_weight (inv);
258 sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1); 335 sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1);
259 } 336 }
337
260 if (op->type == CONTAINER && op->stats.Str) 338 if (op->type == CONTAINER && op->stats.Str)
261 sum = (sum * (100 - op->stats.Str)) / 100; 339 sum = (sum * (100 - op->stats.Str)) / 100;
340
262 if (op->carrying != sum) 341 if (op->carrying != sum)
263 op->carrying = sum; 342 op->carrying = sum;
343
264 return sum; 344 return sum;
265} 345}
266 346
267/** 347/**
268 * Return the outermost environment object for a given object. 348 * Return the outermost environment object for a given object.
366void 446void
367dump_all_objects (void) 447dump_all_objects (void)
368{ 448{
369 object *op; 449 object *op;
370 450
371 for (op = objects; op != NULL; op = op->next) 451 for (op = object::first; op != NULL; op = op->next)
372 { 452 {
373 dump_object (op); 453 dump_object (op);
374 fprintf (logfile, "Object %d\n:%s\n", op->count, errmsg); 454 fprintf (logfile, "Object %d\n:%s\n", op->count, errmsg);
375 } 455 }
376} 456}
402object * 482object *
403find_object (tag_t i) 483find_object (tag_t i)
404{ 484{
405 object *op; 485 object *op;
406 486
407 for (op = objects; op != NULL; op = op->next) 487 for (op = object::first; op != NULL; op = op->next)
408 if (op->count == i) 488 if (op->count == i)
409 break; 489 break;
410 return op; 490 return op;
411} 491}
412 492
417 */ 497 */
418 498
419object * 499object *
420find_object_name (const char *str) 500find_object_name (const char *str)
421{ 501{
422 const char *name = shstr::find (str); 502 shstr_cmp str_ (str);
423 object *op; 503 object *op;
424 504
425 for (op = objects; op != NULL; op = op->next) 505 for (op = object::first; op != NULL; op = op->next)
426 if (&op->name == name) 506 if (op->name == str_)
427 break; 507 break;
428 508
429 return op; 509 return op;
430} 510}
431 511
434{ 514{
435 LOG (llevDebug, "%d allocated objects\n", nrofallocobjects); 515 LOG (llevDebug, "%d allocated objects\n", nrofallocobjects);
436} 516}
437 517
438/* 518/*
439 * Returns the object which this object marks as being the owner.
440 * A id-scheme is used to avoid pointing to objects which have been
441 * freed and are now reused. If this is detected, the owner is
442 * set to NULL, and NULL is returned.
443 * Changed 2004-02-12 - if the player is setting at the play again
444 * prompt, he is removed, and we don't want to treat him as an owner of
445 * anything, so check removed flag. I don't expect that this should break
446 * anything - once an object is removed, it is basically dead anyways.
447 */
448
449object *
450get_owner (object *op)
451{
452 if (op->owner == NULL)
453 return NULL;
454
455 if (!QUERY_FLAG (op->owner, FLAG_FREED) && !QUERY_FLAG (op->owner, FLAG_REMOVED) && op->owner->count == op->ownercount)
456 return op->owner;
457
458 op->owner = NULL;
459 op->ownercount = 0;
460 return NULL;
461}
462
463void
464clear_owner (object *op)
465{
466 if (!op)
467 return;
468
469 if (op->owner && op->ownercount == op->owner->count)
470 op->owner->refcount--;
471
472 op->owner = NULL;
473 op->ownercount = 0;
474}
475
476/*
477 * Sets the owner and sets the skill and exp pointers to owner's current 519 * Sets the owner and sets the skill and exp pointers to owner's current
478 * skill and experience objects. 520 * skill and experience objects.
479 */ 521 */
480void 522void
481set_owner (object *op, object *owner) 523object::set_owner (object *owner)
482{ 524{
483 if (owner == NULL || op == NULL) 525 if (!owner)
484 return; 526 return;
485 527
486 /* next line added to allow objects which own objects */ 528 /* next line added to allow objects which own objects */
487 /* Add a check for ownercounts in here, as I got into an endless loop 529 /* Add a check for ownercounts in here, as I got into an endless loop
488 * with the fireball owning a poison cloud which then owned the 530 * with the fireball owning a poison cloud which then owned the
489 * fireball. I believe that was caused by one of the objects getting 531 * fireball. I believe that was caused by one of the objects getting
490 * freed and then another object replacing it. Since the ownercounts 532 * freed and then another object replacing it. Since the ownercounts
491 * didn't match, this check is valid and I believe that cause is valid. 533 * didn't match, this check is valid and I believe that cause is valid.
492 */ 534 */
493 while (owner->owner && owner != owner->owner && owner->ownercount == owner->owner->count) 535 while (owner->owner)
494 owner = owner->owner; 536 owner = owner->owner;
495 537
496 /* IF the owner still has an owner, we did not resolve to a final owner.
497 * so lets not add to that.
498 */
499 if (owner->owner)
500 return;
501
502 op->owner = owner; 538 this->owner = owner;
503
504 op->ownercount = owner->count;
505 owner->refcount++;
506}
507
508/* Set the owner to clone's current owner and set the skill and experience
509 * objects to clone's objects (typically those objects that where the owner's
510 * current skill and experience objects at the time when clone's owner was
511 * set - not the owner's current skill and experience objects).
512 *
513 * Use this function if player created an object (e.g. fire bullet, swarm
514 * spell), and this object creates further objects whose kills should be
515 * accounted for the player's original skill, even if player has changed
516 * skills meanwhile.
517 */
518void
519copy_owner (object *op, object *clone)
520{
521 object *owner = get_owner (clone);
522
523 if (owner == NULL)
524 {
525 /* players don't have owners - they own themselves. Update
526 * as appropriate.
527 */
528 if (clone->type == PLAYER)
529 owner = clone;
530 else
531 return;
532 }
533
534 set_owner (op, owner);
535} 539}
536 540
537/* Zero the key_values on op, decrementing the shared-string 541/* Zero the key_values on op, decrementing the shared-string
538 * refcounts and freeing the links. 542 * refcounts and freeing the links.
539 */ 543 */
555{ 559{
556 attachable_base::clear (); 560 attachable_base::clear ();
557 561
558 free_key_values (this); 562 free_key_values (this);
559 563
560 clear_owner (this); 564 owner = 0;
561
562 name = 0; 565 name = 0;
563 name_pl = 0; 566 name_pl = 0;
564 title = 0; 567 title = 0;
565 race = 0; 568 race = 0;
566 slaying = 0; 569 slaying = 0;
567 skill = 0; 570 skill = 0;
568 msg = 0; 571 msg = 0;
569 lore = 0; 572 lore = 0;
570 custom_name = 0; 573 custom_name = 0;
571 materialname = 0; 574 materialname = 0;
575 contr = 0;
576 below = 0;
577 above = 0;
578 inv = 0;
579 container = 0;
580 env = 0;
581 more = 0;
582 head = 0;
583 map = 0;
584 active_next = 0;
585 active_prev = 0;
572 586
573 memset (static_cast < object_pod * >(this), 0, sizeof (object_pod)); 587 memset (static_cast<object_pod *>(this), 0, sizeof (object_pod));
574 588
575 SET_FLAG (this, FLAG_REMOVED); 589 SET_FLAG (this, FLAG_REMOVED);
590
591 /* What is not cleared is next, prev, and count */
592
593 expmul = 1.0;
594 face = blank_face;
595
596 if (settings.casting_time)
597 casting_time = -1;
576} 598}
577 599
578void object::clone (object *destination) 600void object::clone (object *destination)
579{ 601{
580 *(object_copy *) destination = *this; 602 *(object_copy *)destination = *this;
581 *(object_pod *) destination = *this; 603 *(object_pod *)destination = *this;
582 604
583 if (self || cb) 605 if (self || cb)
584 INVOKE_OBJECT (CLONE, this, ARG_OBJECT (destination)); 606 INVOKE_OBJECT (CLONE, this, ARG_OBJECT (destination));
585}
586
587/*
588 * clear_object() frees everything allocated by an object, and also
589 * clears all variables and flags to default settings.
590 */
591
592void
593clear_object (object *op)
594{
595 op->clear ();
596
597 op->contr = NULL;
598 op->below = NULL;
599 op->above = NULL;
600 op->inv = NULL;
601 op->container = NULL;
602 op->env = NULL;
603 op->more = NULL;
604 op->head = NULL;
605 op->map = NULL;
606 op->refcount = 0;
607 op->active_next = NULL;
608 op->active_prev = NULL;
609 /* What is not cleared is next, prev, and count */
610
611 op->expmul = 1.0;
612 op->face = blank_face;
613 op->attacked_by_count = -1;
614
615 if (settings.casting_time)
616 op->casting_time = -1;
617} 607}
618 608
619/* 609/*
620 * copy object first frees everything allocated by the second object, 610 * copy object first frees everything allocated by the second object,
621 * and then copies the contends of the first object into the second 611 * and then copies the contends of the first object into the second
622 * object, allocating what needs to be allocated. Basically, any 612 * object, allocating what needs to be allocated. Basically, any
623 * data that is malloc'd needs to be re-malloc/copied. Otherwise, 613 * data that is malloc'd needs to be re-malloc/copied. Otherwise,
624 * if the first object is freed, the pointers in the new object 614 * if the first object is freed, the pointers in the new object
625 * will point at garbage. 615 * will point at garbage.
626 */ 616 */
627
628void 617void
629copy_object (object *op2, object *op) 618copy_object (object *op2, object *op)
630{ 619{
631 bool is_freed = QUERY_FLAG (op, FLAG_FREED); 620 bool is_freed = QUERY_FLAG (op, FLAG_FREED);
632 bool is_removed = QUERY_FLAG (op, FLAG_REMOVED); 621 bool is_removed = QUERY_FLAG (op, FLAG_REMOVED);
692/* 681/*
693 * Updates the speed of an object. If the speed changes from 0 to another 682 * Updates the speed of an object. If the speed changes from 0 to another
694 * value, or vice versa, then add/remove the object from the active list. 683 * value, or vice versa, then add/remove the object from the active list.
695 * This function needs to be called whenever the speed of an object changes. 684 * This function needs to be called whenever the speed of an object changes.
696 */ 685 */
697
698void 686void
699update_ob_speed (object *op) 687update_ob_speed (object *op)
700{ 688{
701 extern int arch_init; 689 extern int arch_init;
702 690
711 abort (); 699 abort ();
712#else 700#else
713 op->speed = 0; 701 op->speed = 0;
714#endif 702#endif
715 } 703 }
704
716 if (arch_init) 705 if (arch_init)
717 {
718 return; 706 return;
719 } 707
720 if (FABS (op->speed) > MIN_ACTIVE_SPEED) 708 if (FABS (op->speed) > MIN_ACTIVE_SPEED)
721 { 709 {
722 /* If already on active list, don't do anything */ 710 /* If already on active list, don't do anything */
723 if (op->active_next || op->active_prev || op == active_objects) 711 if (op->active_next || op->active_prev || op == active_objects)
724 return; 712 return;
725 713
726 /* process_events() expects us to insert the object at the beginning 714 /* process_events() expects us to insert the object at the beginning
727 * of the list. */ 715 * of the list. */
728 op->active_next = active_objects; 716 op->active_next = active_objects;
717
729 if (op->active_next != NULL) 718 if (op->active_next != NULL)
730 op->active_next->active_prev = op; 719 op->active_next->active_prev = op;
720
731 active_objects = op; 721 active_objects = op;
732 } 722 }
733 else 723 else
734 { 724 {
735 /* If not on the active list, nothing needs to be done */ 725 /* If not on the active list, nothing needs to be done */
737 return; 727 return;
738 728
739 if (op->active_prev == NULL) 729 if (op->active_prev == NULL)
740 { 730 {
741 active_objects = op->active_next; 731 active_objects = op->active_next;
732
742 if (op->active_next != NULL) 733 if (op->active_next != NULL)
743 op->active_next->active_prev = NULL; 734 op->active_next->active_prev = NULL;
744 } 735 }
745 else 736 else
746 { 737 {
747 op->active_prev->active_next = op->active_next; 738 op->active_prev->active_next = op->active_next;
739
748 if (op->active_next) 740 if (op->active_next)
749 op->active_next->active_prev = op->active_prev; 741 op->active_next->active_prev = op->active_prev;
750 } 742 }
743
751 op->active_next = NULL; 744 op->active_next = NULL;
752 op->active_prev = NULL; 745 op->active_prev = NULL;
753 } 746 }
754} 747}
755 748
901 894
902 if (op->more != NULL) 895 if (op->more != NULL)
903 update_object (op->more, action); 896 update_object (op->more, action);
904} 897}
905 898
906static unordered_vector < object *>mortals; 899object::vector object::mortals;
907static 900object::vector object::objects; // not yet used
908std::vector < object *> 901object *object::first;
909 freed;
910 902
911void object::free_mortals () 903void object::free_mortals ()
912{ 904{
913 for (unordered_vector < object *>::iterator i = mortals.begin (); i != mortals.end ();) 905 for (AUTODECL (i, mortals.begin ()); i != mortals.end ();)
914 if (!(*i)->refcount) 906 if ((*i)->refcnt)
907 ++i; // further delay freeing
908 else
915 { 909 {
916 freed.push_back (*i); 910 delete *i;
917 mortals.erase (i); 911 mortals.erase (i);
918 } 912 }
919 else 913
920 ++i; 914 static int lastmortals = 0;//D
915
916 if (mortals.size() != lastmortals)//D
917 {
918 lastmortals = mortals.size ();//D
919 LOG (llevDebug, "%d objects in mortal queue\n", lastmortals);//D
920 }
921} 921}
922 922
923object::object () 923object::object ()
924{ 924{
925 SET_FLAG (this, FLAG_REMOVED); 925 SET_FLAG (this, FLAG_REMOVED);
926 926
927 expmul = 1.0; 927 expmul = 1.0;
928 face = blank_face; 928 face = blank_face;
929 attacked_by_count = -1;
930} 929}
931 930
932object::~object () 931object::~object ()
933{ 932{
934 free_key_values (this); 933 free_key_values (this);
935} 934}
936 935
937void object::link () 936void object::link ()
938{ 937{
939 count = ++ob_count; 938 count = ++ob_count;
939 uuid = gen_uuid ();
940 940
941 prev = 0; 941 prev = 0;
942 next = objects; 942 next = object::first;
943 943
944 if (objects) 944 if (object::first)
945 objects->prev = this; 945 object::first->prev = this;
946 946
947 objects = this; 947 object::first = this;
948} 948}
949 949
950void object::unlink () 950void object::unlink ()
951{ 951{
952 count = 0; 952 //count = 0;//D
953 if (!prev && !next) return;//D
954
955 if (this == object::first)
956 object::first = next;
953 957
954 /* Remove this object from the list of used objects */ 958 /* Remove this object from the list of used objects */
955 if (prev)
956 {
957 prev->next = next; 959 if (prev) prev->next = next;
960 if (next) next->prev = prev;
961
958 prev = 0; 962 prev = 0;
959 }
960
961 if (next)
962 {
963 next->prev = prev;
964 next = 0; 963 next = 0;
965 }
966
967 if (this == objects)
968 objects = next;
969} 964}
970 965
971object *object::create () 966object *object::create ()
972{ 967{
973 object *
974 op;
975
976 if (freed.empty ())
977 op = new object; 968 object *op = new object;
978
979 else
980 {
981 // highly annoying, but the only way to get it stable right now
982 op = freed.back ();
983 freed.pop_back ();
984 op->~object ();
985 new ((void *) op) object;
986 }
987
988 op->link (); 969 op->link ();
989 return op; 970 return op;
990} 971}
991 972
992/* 973/*
1002void object::free (bool free_inventory) 983void object::free (bool free_inventory)
1003{ 984{
1004 if (QUERY_FLAG (this, FLAG_FREED)) 985 if (QUERY_FLAG (this, FLAG_FREED))
1005 return; 986 return;
1006 987
988 if (QUERY_FLAG (this, FLAG_FRIENDLY))
989 remove_friendly_object (this);
990
1007 if (!QUERY_FLAG (this, FLAG_REMOVED)) 991 if (!QUERY_FLAG (this, FLAG_REMOVED))
1008 remove_ob (this); 992 remove_ob (this);
1009
1010 if (QUERY_FLAG (this, FLAG_FRIENDLY))
1011 remove_friendly_object (this);
1012 993
1013 SET_FLAG (this, FLAG_FREED); 994 SET_FLAG (this, FLAG_FREED);
1014 995
1015 if (more) 996 if (more)
1016 { 997 {
1022 { 1003 {
1023 /* Only if the space blocks everything do we not process - 1004 /* Only if the space blocks everything do we not process -
1024 * if some form of movement is allowed, let objects 1005 * if some form of movement is allowed, let objects
1025 * drop on that space. 1006 * drop on that space.
1026 */ 1007 */
1027 if (free_inventory || !map || map->in_memory != MAP_IN_MEMORY || (GET_MAP_MOVE_BLOCK (map, x, y) == MOVE_ALL)) 1008 if (free_inventory || !map || map->in_memory != MAP_IN_MEMORY || GET_MAP_MOVE_BLOCK (map, x, y) == MOVE_ALL)
1028 { 1009 {
1029 object *op = inv; 1010 object *op = inv;
1030 1011
1031 while (op) 1012 while (op)
1032 { 1013 {
1058 op = tmp; 1039 op = tmp;
1059 } 1040 }
1060 } 1041 }
1061 } 1042 }
1062 1043
1063 clear_owner (this); 1044 // clear those pointers that likely might have circular references to us
1045 owner = 0;
1046 enemy = 0;
1047 attacked_by = 0;
1064 1048
1065 /* Remove object from the active list */ 1049 /* Remove object from the active list */
1066 speed = 0; 1050 speed = 0;
1067 update_ob_speed (this); 1051 update_ob_speed (this);
1068 1052
1080sub_weight (object *op, signed long weight) 1064sub_weight (object *op, signed long weight)
1081{ 1065{
1082 while (op != NULL) 1066 while (op != NULL)
1083 { 1067 {
1084 if (op->type == CONTAINER) 1068 if (op->type == CONTAINER)
1085 {
1086 weight = (signed long) (weight * (100 - op->stats.Str) / 100); 1069 weight = (signed long) (weight * (100 - op->stats.Str) / 100);
1087 } 1070
1088 op->carrying -= weight; 1071 op->carrying -= weight;
1089 op = op->env; 1072 op = op->env;
1090 } 1073 }
1091} 1074}
1092 1075
1100 */ 1083 */
1101 1084
1102void 1085void
1103remove_ob (object *op) 1086remove_ob (object *op)
1104{ 1087{
1088 object *tmp, *last = 0;
1105 object * 1089 object *otmp;
1106 tmp, *
1107 last = NULL;
1108 object *
1109 otmp;
1110 1090
1111 tag_t 1091 tag_t tag;
1112 tag;
1113 int
1114 check_walk_off; 1092 int check_walk_off;
1115 mapstruct * 1093 mapstruct *m;
1116 m;
1117 1094
1118 sint16 1095 sint16 x, y;
1119 x,
1120 y;
1121 1096
1122 if (QUERY_FLAG (op, FLAG_REMOVED)) 1097 if (QUERY_FLAG (op, FLAG_REMOVED))
1123 return; 1098 return;
1124 1099
1125 SET_FLAG (op, FLAG_REMOVED); 1100 SET_FLAG (op, FLAG_REMOVED);
1288 * This function goes through all objects below and including top, and 1263 * This function goes through all objects below and including top, and
1289 * merges op to the first matching object. 1264 * merges op to the first matching object.
1290 * If top is NULL, it is calculated. 1265 * If top is NULL, it is calculated.
1291 * Returns pointer to object if it succeded in the merge, otherwise NULL 1266 * Returns pointer to object if it succeded in the merge, otherwise NULL
1292 */ 1267 */
1293
1294object * 1268object *
1295merge_ob (object *op, object *top) 1269merge_ob (object *op, object *top)
1296{ 1270{
1297 if (!op->nrof) 1271 if (!op->nrof)
1298 return 0; 1272 return 0;
1314 free_object (op); 1288 free_object (op);
1315 return top; 1289 return top;
1316 } 1290 }
1317 } 1291 }
1318 1292
1319 return NULL; 1293 return 0;
1320} 1294}
1321 1295
1322/* 1296/*
1323 * same as insert_ob_in_map except it handle separate coordinates and do a clean 1297 * same as insert_ob_in_map except it handle separate coordinates and do a clean
1324 * job preparing multi-part monsters 1298 * job preparing multi-part monsters
2719 2693
2720 if (tempfile == NULL) 2694 if (tempfile == NULL)
2721 { 2695 {
2722 LOG (llevError, "Error - Unable to access load object temp file\n"); 2696 LOG (llevError, "Error - Unable to access load object temp file\n");
2723 return NULL; 2697 return NULL;
2724 }; 2698 }
2699
2725 fprintf (tempfile, obstr); 2700 fprintf (tempfile, obstr);
2726 fclose (tempfile); 2701 fclose (tempfile);
2727 2702
2728 op = get_object (); 2703 op = get_object ();
2729 2704
2786 * The returned string is shared. 2761 * The returned string is shared.
2787 */ 2762 */
2788const char * 2763const char *
2789get_ob_key_value (const object *op, const char *const key) 2764get_ob_key_value (const object *op, const char *const key)
2790{ 2765{
2791 key_value * 2766 key_value *link;
2792 link; 2767 shstr_cmp canonical_key (key);
2793 const char *
2794 canonical_key;
2795 2768
2796 canonical_key = shstr::find (key);
2797
2798 if (canonical_key == NULL) 2769 if (!canonical_key)
2799 { 2770 {
2800 /* 1. There being a field named key on any object 2771 /* 1. There being a field named key on any object
2801 * implies there'd be a shared string to find. 2772 * implies there'd be a shared string to find.
2802 * 2. Since there isn't, no object has this field. 2773 * 2. Since there isn't, no object has this field.
2803 * 3. Therefore, *this* object doesn't have this field. 2774 * 3. Therefore, *this* object doesn't have this field.
2804 */ 2775 */
2805 return NULL; 2776 return 0;
2806 } 2777 }
2807 2778
2808 /* This is copied from get_ob_key_link() above - 2779 /* This is copied from get_ob_key_link() above -
2809 * only 4 lines, and saves the function call overhead. 2780 * only 4 lines, and saves the function call overhead.
2810 */ 2781 */
2811 for (link = op->key_values; link != NULL; link = link->next) 2782 for (link = op->key_values; link; link = link->next)
2812 {
2813 if (link->key == canonical_key) 2783 if (link->key == canonical_key)
2814 {
2815 return link->value; 2784 return link->value;
2816 } 2785
2817 }
2818 return NULL; 2786 return 0;
2819} 2787}
2820 2788
2821 2789
2822/* 2790/*
2823 * Updates the canonical_key in op to value. 2791 * Updates the canonical_key in op to value.
2908{ 2876{
2909 shstr key_ (key); 2877 shstr key_ (key);
2910 2878
2911 return set_ob_key_value_s (op, key_, value, add_key); 2879 return set_ob_key_value_s (op, key_, value, add_key);
2912} 2880}
2881
2882object::depth_iterator::depth_iterator (object *container)
2883: iterator_base (container)
2884{
2885 while (item->inv)
2886 item = item->inv;
2887}
2888
2889void
2890object::depth_iterator::next ()
2891{
2892 if (item->below)
2893 {
2894 item = item->below;
2895
2896 while (item->inv)
2897 item = item->inv;
2898 }
2899 else
2900 item = item->env;
2901}
2902
2903// return a suitable string describing an objetc in enough detail to find it
2904const char *
2905object::debug_desc (char *info) const
2906{
2907 char info2[256 * 3];
2908 char *p = info;
2909
2910 p += snprintf (p, 256, "%d=\"%s%s%s\"",
2911 count,
2912 &name,
2913 title ? " " : "",
2914 title ? (const char *)title : "");
2915
2916 if (env)
2917 p += snprintf (p, 256, "(in %s)", env->debug_desc (info2));
2918
2919 if (map)
2920 p += snprintf (p, 256, "(on %s@%d+%d)", map->path, x, y);
2921
2922 return info;
2923}
2924
2925const char *
2926object::debug_desc () const
2927{
2928 static char info[256 * 3];
2929 return debug_desc (info);
2930}
2931

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines