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.34 by root, Tue Sep 12 01:09:53 2006 UTC vs.
Revision 1.48 by root, Thu Sep 14 23:13:48 2006 UTC

1
2/* 1/*
3 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
4 3
5 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 4 Copyright (C) 2001 Mark Wedel & Crossfire Development Team
6 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
17 16
18 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 20
22 The authors can be reached via e-mail at crossfire-devel@real-time.com 21 The authors can be reached via e-mail at <crossfire@schmorp.de>
23*/ 22*/
24 23
25/* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects. 24/* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
26 sub/add_weight will transcend the environment updating the carrying 25 sub/add_weight will transcend the environment updating the carrying
27 variable. */ 26 variable. */
32#include <object.h> 31#include <object.h>
33#include <funcpoint.h> 32#include <funcpoint.h>
34#include <loader.h> 33#include <loader.h>
35 34
36int nrofallocobjects = 0; 35int nrofallocobjects = 0;
36static UUID uuid;
37const uint64 UUID_SKIP = 1<<19;
37 38
38object *objects; /* Pointer to the list of used objects */
39object *active_objects; /* List of active objects that need to be processed */ 39object *active_objects; /* List of active objects that need to be processed */
40 40
41short 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, 41short 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,
42 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1 42 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}; 43};
49}; 49};
50int freedir[SIZEOFFREE] = { 50int freedir[SIZEOFFREE] = {
51 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, 51 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 1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8 52 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}; 53};
54
55static void
56write_uuid (void)
57{
58 char filename1[MAX_BUF], filename2[MAX_BUF];
59
60 sprintf (filename1, "%s/uuid", settings.localdir);
61 sprintf (filename2, "%s/uuid~", settings.localdir);
62
63 FILE *fp;
64
65 if (!(fp = fopen (filename2, "w")))
66 {
67 LOG (llevError, "ERROR: cannot open %s for writing, unable to write UUID!\n", filename2);
68 return;
69 }
70
71 fprintf (fp, "<1,%llx>\n", (unsigned long long)uuid.seq + UUID_SKIP * 2);
72 fclose (fp);
73 rename (filename2, filename1);
74}
75
76static void
77read_uuid (void)
78{
79 char filename[MAX_BUF];
80
81 sprintf (filename, "%s/uuid", settings.localdir);
82
83 FILE *fp;
84
85 if (!(fp = fopen (filename, "r")))
86 {
87 if (errno == ENOENT)
88 {
89 LOG (llevInfo, "RESET uid to 1\n");
90 uuid.seq = 0;
91 write_uuid ();
92 return;
93 }
94
95 LOG (llevError, "FATAL: cannot open %s for reading!\n", filename);
96 _exit (1);
97 }
98
99 int version;
100 unsigned long long uid;
101 if (2 != fscanf (fp, "<%d,%llx>\n", &version, &uid) || version != 1)
102 {
103 LOG (llevError, "FATAL: error reading uid from %s!\n", filename);
104 _exit (1);
105 }
106
107 uuid.seq = uid;
108 write_uuid ();
109 LOG (llevDebug, "read UID: %lld\n", uid);
110 fclose (fp);
111}
112
113UUID
114gen_uuid ()
115{
116 UUID uid;
117
118 uid.seq = ++uuid.seq;
119
120 if (!(uuid.seq & (UUID_SKIP - 1)))
121 write_uuid ();
122
123 return uid;
124}
125
126void
127init_uuid ()
128{
129 read_uuid ();
130}
54 131
55/* Returns TRUE if every key_values in wants has a partner with the same value in has. */ 132/* Returns TRUE if every key_values in wants has a partner with the same value in has. */
56static int 133static int
57compare_ob_value_lists_one (const object *wants, const object *has) 134compare_ob_value_lists_one (const object *wants, const object *has)
58{ 135{
254 { 331 {
255 if (inv->inv) 332 if (inv->inv)
256 sum_weight (inv); 333 sum_weight (inv);
257 sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1); 334 sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1);
258 } 335 }
336
259 if (op->type == CONTAINER && op->stats.Str) 337 if (op->type == CONTAINER && op->stats.Str)
260 sum = (sum * (100 - op->stats.Str)) / 100; 338 sum = (sum * (100 - op->stats.Str)) / 100;
339
261 if (op->carrying != sum) 340 if (op->carrying != sum)
262 op->carrying = sum; 341 op->carrying = sum;
342
263 return sum; 343 return sum;
264} 344}
265 345
266/** 346/**
267 * Return the outermost environment object for a given object. 347 * Return the outermost environment object for a given object.
365void 445void
366dump_all_objects (void) 446dump_all_objects (void)
367{ 447{
368 object *op; 448 object *op;
369 449
370 for (op = objects; op != NULL; op = op->next) 450 for (op = object::first; op != NULL; op = op->next)
371 { 451 {
372 dump_object (op); 452 dump_object (op);
373 fprintf (logfile, "Object %d\n:%s\n", op->count, errmsg); 453 fprintf (logfile, "Object %s\n", errmsg);
374 } 454 }
375} 455}
376 456
377/* 457/*
378 * get_nearest_part(multi-object, object 2) returns the part of the 458 * get_nearest_part(multi-object, object 2) returns the part of the
401object * 481object *
402find_object (tag_t i) 482find_object (tag_t i)
403{ 483{
404 object *op; 484 object *op;
405 485
406 for (op = objects; op != NULL; op = op->next) 486 for (op = object::first; op != NULL; op = op->next)
407 if (op->count == i) 487 if (op->count == i)
408 break; 488 break;
489
409 return op; 490 return op;
410} 491}
411 492
412/* 493/*
413 * Returns the first object which has a name equal to the argument. 494 * Returns the first object which has a name equal to the argument.
416 */ 497 */
417 498
418object * 499object *
419find_object_name (const char *str) 500find_object_name (const char *str)
420{ 501{
421 const char *name = shstr::find (str); 502 shstr_cmp str_ (str);
422 object *op; 503 object *op;
423 504
424 for (op = objects; op != NULL; op = op->next) 505 for (op = object::first; op != NULL; op = op->next)
425 if (&op->name == name) 506 if (op->name == str_)
426 break; 507 break;
427 508
428 return op; 509 return op;
429} 510}
430 511
431void 512void
432free_all_object_data () 513free_all_object_data ()
433{ 514{
434 LOG (llevDebug, "%d allocated objects\n", nrofallocobjects); 515 LOG (llevDebug, "%d allocated objects\n", nrofallocobjects);
435}
436
437/*
438 * Returns the object which this object marks as being the owner.
439 * A id-scheme is used to avoid pointing to objects which have been
440 * freed and are now reused. If this is detected, the owner is
441 * set to NULL, and NULL is returned.
442 * Changed 2004-02-12 - if the player is setting at the play again
443 * prompt, he is removed, and we don't want to treat him as an owner of
444 * anything, so check removed flag. I don't expect that this should break
445 * anything - once an object is removed, it is basically dead anyways.
446 */
447object *
448object::get_owner ()
449{
450 if (!owner
451 || QUERY_FLAG (owner, FLAG_FREED)
452 || QUERY_FLAG (owner, FLAG_REMOVED))
453 owner = 0;
454
455 return owner;
456} 516}
457 517
458/* 518/*
459 * 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
460 * skill and experience objects. 520 * skill and experience objects.
530 590
531 /* What is not cleared is next, prev, and count */ 591 /* What is not cleared is next, prev, and count */
532 592
533 expmul = 1.0; 593 expmul = 1.0;
534 face = blank_face; 594 face = blank_face;
535 attacked_by_count = -1;
536 595
537 if (settings.casting_time) 596 if (settings.casting_time)
538 casting_time = -1; 597 casting_time = -1;
539} 598}
540 599
835 894
836 if (op->more != NULL) 895 if (op->more != NULL)
837 update_object (op->more, action); 896 update_object (op->more, action);
838} 897}
839 898
840static unordered_vector<object *> mortals; 899object::vector object::mortals;
841static std::vector<object *> freed; 900object::vector object::objects; // not yet used
901object *object::first;
842 902
843void object::free_mortals () 903void object::free_mortals ()
844{ 904{
845 for (unordered_vector<object *>::iterator i = mortals.begin (); i != mortals.end ();) 905 for (AUTODECL (i, mortals.begin ()); i != mortals.end ();)
846 if ((*i)->refcnt) 906 if ((*i)->refcnt)
847 ++i; // further delay freeing 907 ++i; // further delay freeing
848 else 908 else
849 { 909 {
850 freed.push_back (*i);//D
851 //delete *i; 910 delete *i;
852 mortals.erase (i); 911 mortals.erase (i);
853 } 912 }
854 913
914 static int lastmortals = 0;//D
915
855 if (mortals.size())//D 916 if (mortals.size() != lastmortals)//D
917 {
918 lastmortals = mortals.size ();//D
856 LOG (llevDebug, "%d objects in mortal queue\n", mortals.size());//D 919 LOG (llevDebug, "%d objects in mortal queue\n", lastmortals);//D
920 }
857} 921}
858 922
859object::object () 923object::object ()
860{ 924{
861 SET_FLAG (this, FLAG_REMOVED); 925 SET_FLAG (this, FLAG_REMOVED);
862 926
863 expmul = 1.0; 927 expmul = 1.0;
864 face = blank_face; 928 face = blank_face;
865 attacked_by_count = -1;
866} 929}
867 930
868object::~object () 931object::~object ()
869{ 932{
870 free_key_values (this); 933 free_key_values (this);
871} 934}
872 935
873void object::link () 936void object::link ()
874{ 937{
875 count = ++ob_count; 938 count = ++ob_count;
939 uuid = gen_uuid ();
876 940
877 prev = 0; 941 prev = 0;
878 next = objects; 942 next = object::first;
879 943
880 if (objects) 944 if (object::first)
881 objects->prev = this; 945 object::first->prev = this;
882 946
883 objects = this; 947 object::first = this;
884} 948}
885 949
886void object::unlink () 950void object::unlink ()
887{ 951{
888 count = 0; 952 if (this == object::first)
953 object::first = next;
889 954
890 /* Remove this object from the list of used objects */ 955 /* Remove this object from the list of used objects */
891 if (prev)
892 {
893 prev->next = next; 956 if (prev) prev->next = next;
957 if (next) next->prev = prev;
958
894 prev = 0; 959 prev = 0;
895 }
896
897 if (next)
898 {
899 next->prev = prev;
900 next = 0; 960 next = 0;
901 }
902
903 if (this == objects)
904 objects = next;
905} 961}
906 962
907object *object::create () 963object *object::create ()
908{ 964{
909 object *op;
910
911 if (freed.empty ())
912 op = new object; 965 object *op = new object;
913 else
914 {
915 // highly annoying, but the only way to get it stable right now
916 op = freed.back ();
917 freed.pop_back ();
918 op->~object ();
919 new ((void *) op) object;
920 }
921
922 op->link (); 966 op->link ();
923 return op; 967 return op;
924} 968}
925 969
926/* 970/*
992 op = tmp; 1036 op = tmp;
993 } 1037 }
994 } 1038 }
995 } 1039 }
996 1040
1041 // clear those pointers that likely might have circular references to us
997 owner = 0; 1042 owner = 0;
1043 enemy = 0;
1044 attacked_by = 0;
998 1045
999 /* Remove object from the active list */ 1046 /* Remove object from the active list */
1000 speed = 0; 1047 speed = 0;
1001 update_ob_speed (this); 1048 update_ob_speed (this);
1002 1049
1014sub_weight (object *op, signed long weight) 1061sub_weight (object *op, signed long weight)
1015{ 1062{
1016 while (op != NULL) 1063 while (op != NULL)
1017 { 1064 {
1018 if (op->type == CONTAINER) 1065 if (op->type == CONTAINER)
1019 {
1020 weight = (signed long) (weight * (100 - op->stats.Str) / 100); 1066 weight = (signed long) (weight * (100 - op->stats.Str) / 100);
1021 } 1067
1022 op->carrying -= weight; 1068 op->carrying -= weight;
1023 op = op->env; 1069 op = op->env;
1024 } 1070 }
1025} 1071}
1026 1072
1034 */ 1080 */
1035 1081
1036void 1082void
1037remove_ob (object *op) 1083remove_ob (object *op)
1038{ 1084{
1085 object *tmp, *last = 0;
1039 object * 1086 object *otmp;
1040 tmp, *
1041 last = NULL;
1042 object *
1043 otmp;
1044 1087
1045 tag_t
1046 tag;
1047 int
1048 check_walk_off; 1088 int check_walk_off;
1049 mapstruct * 1089 mapstruct *m;
1050 m;
1051 1090
1052 sint16 1091 sint16 x, y;
1053 x,
1054 y;
1055 1092
1056 if (QUERY_FLAG (op, FLAG_REMOVED)) 1093 if (QUERY_FLAG (op, FLAG_REMOVED))
1057 return; 1094 return;
1058 1095
1059 SET_FLAG (op, FLAG_REMOVED); 1096 SET_FLAG (op, FLAG_REMOVED);
1152 op->below = 0; 1189 op->below = 0;
1153 1190
1154 if (op->map->in_memory == MAP_SAVING) 1191 if (op->map->in_memory == MAP_SAVING)
1155 return; 1192 return;
1156 1193
1157 tag = op->count;
1158 check_walk_off = !QUERY_FLAG (op, FLAG_NO_APPLY); 1194 check_walk_off = !QUERY_FLAG (op, FLAG_NO_APPLY);
1159 1195
1160 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) 1196 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1161 { 1197 {
1162 /* No point updating the players look faces if he is the object 1198 /* No point updating the players look faces if he is the object
1181 /* See if player moving off should effect something */ 1217 /* See if player moving off should effect something */
1182 if (check_walk_off && ((op->move_type & tmp->move_off) && (op->move_type & ~tmp->move_off & ~tmp->move_block) == 0)) 1218 if (check_walk_off && ((op->move_type & tmp->move_off) && (op->move_type & ~tmp->move_off & ~tmp->move_block) == 0))
1183 { 1219 {
1184 move_apply (tmp, op, NULL); 1220 move_apply (tmp, op, NULL);
1185 1221
1186 if (was_destroyed (op, tag)) 1222 if (op->destroyed ());
1187 {
1188 LOG (llevError, "BUG: remove_ob(): name %s, archname %s destroyed " "leaving object\n", &tmp->name, &tmp->arch->name); 1223 LOG (llevError, "BUG: remove_ob(): name %s, archname %s destroyed " "leaving object\n", &tmp->name, &tmp->arch->name);
1189 }
1190 } 1224 }
1191 1225
1192 /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */ 1226 /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
1193 1227
1194 if (tmp->above == tmp) 1228 if (tmp->above == tmp)
1222 * This function goes through all objects below and including top, and 1256 * This function goes through all objects below and including top, and
1223 * merges op to the first matching object. 1257 * merges op to the first matching object.
1224 * If top is NULL, it is calculated. 1258 * If top is NULL, it is calculated.
1225 * Returns pointer to object if it succeded in the merge, otherwise NULL 1259 * Returns pointer to object if it succeded in the merge, otherwise NULL
1226 */ 1260 */
1227
1228object * 1261object *
1229merge_ob (object *op, object *top) 1262merge_ob (object *op, object *top)
1230{ 1263{
1231 if (!op->nrof) 1264 if (!op->nrof)
1232 return 0; 1265 return 0;
1248 free_object (op); 1281 free_object (op);
1249 return top; 1282 return top;
1250 } 1283 }
1251 } 1284 }
1252 1285
1253 return NULL; 1286 return 0;
1254} 1287}
1255 1288
1256/* 1289/*
1257 * same as insert_ob_in_map except it handle separate coordinates and do a clean 1290 * same as insert_ob_in_map except it handle separate coordinates and do a clean
1258 * job preparing multi-part monsters 1291 * job preparing multi-part monsters
1585 remove_ob (tmp); 1618 remove_ob (tmp);
1586 free_object (tmp); 1619 free_object (tmp);
1587 } 1620 }
1588 } 1621 }
1589 1622
1590 tmp1 = arch_to_object (find_archetype (arch_string)); 1623 tmp1 = arch_to_object (archetype::find (arch_string));
1591 1624
1592 tmp1->x = op->x; 1625 tmp1->x = op->x;
1593 tmp1->y = op->y; 1626 tmp1->y = op->y;
1594 insert_ob_in_map (tmp1, op->map, op, 0); 1627 insert_ob_in_map (tmp1, op->map, op, 0);
1595} 1628}
1894 */ 1927 */
1895 1928
1896int 1929int
1897check_move_on (object *op, object *originator) 1930check_move_on (object *op, object *originator)
1898{ 1931{
1899 object * 1932 object *tmp;
1900 tmp; 1933 mapstruct *m = op->map;
1901 tag_t
1902 tag;
1903 mapstruct *
1904 m = op->map;
1905 int
1906 x = op->x, y = op->y; 1934 int x = op->x, y = op->y;
1907 1935
1908 MoveType 1936 MoveType move_on, move_slow, move_block;
1909 move_on,
1910 move_slow,
1911 move_block;
1912 1937
1913 if (QUERY_FLAG (op, FLAG_NO_APPLY)) 1938 if (QUERY_FLAG (op, FLAG_NO_APPLY))
1914 return 0; 1939 return 0;
1915
1916 tag = op->count;
1917 1940
1918 move_on = GET_MAP_MOVE_ON (op->map, op->x, op->y); 1941 move_on = GET_MAP_MOVE_ON (op->map, op->x, op->y);
1919 move_slow = GET_MAP_MOVE_SLOW (op->map, op->x, op->y); 1942 move_slow = GET_MAP_MOVE_SLOW (op->map, op->x, op->y);
1920 move_block = GET_MAP_MOVE_BLOCK (op->map, op->x, op->y); 1943 move_block = GET_MAP_MOVE_BLOCK (op->map, op->x, op->y);
1921 1944
1982 if ((!op->move_type && tmp->move_on & MOVE_WALK) || 2005 if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
1983 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0)) 2006 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1984 { 2007 {
1985 move_apply (tmp, op, originator); 2008 move_apply (tmp, op, originator);
1986 2009
1987 if (was_destroyed (op, tag)) 2010 if (op->destroyed ())
1988 return 1; 2011 return 1;
1989 2012
1990 /* what the person/creature stepped onto has moved the object 2013 /* what the person/creature stepped onto has moved the object
1991 * someplace new. Don't process any further - if we did, 2014 * someplace new. Don't process any further - if we did,
1992 * have a feeling strange problems would result. 2015 * have a feeling strange problems would result.
2606 if (prev) 2629 if (prev)
2607 prev->more = tmp; 2630 prev->more = tmp;
2608 prev = tmp; 2631 prev = tmp;
2609 } 2632 }
2610 2633
2611 /*** copy inventory ***/
2612 for (item = src->inv; item; item = item->below) 2634 for (item = src->inv; item; item = item->below)
2613 {
2614 (void) insert_ob_in_ob (object_create_clone (item), dst); 2635 insert_ob_in_ob (object_create_clone (item), dst);
2615 }
2616 2636
2617 return dst; 2637 return dst;
2618} 2638}
2619 2639
2620/* return true if the object was destroyed, 0 otherwise */
2621int
2622was_destroyed (const object *op, tag_t old_tag)
2623{
2624 /* checking for FLAG_FREED isn't necessary, but makes this function more
2625 * robust */
2626 return op->count != old_tag || QUERY_FLAG (op, FLAG_FREED);
2627}
2628
2629/* GROS - Creates an object using a string representing its content. */ 2640/* GROS - Creates an object using a string representing its content. */
2630
2631/* Basically, we save the content of the string to a temp file, then call */ 2641/* Basically, we save the content of the string to a temp file, then call */
2632
2633/* load_object on it. I admit it is a highly inefficient way to make things, */ 2642/* load_object on it. I admit it is a highly inefficient way to make things, */
2634
2635/* but it was simple to make and allows reusing the load_object function. */ 2643/* but it was simple to make and allows reusing the load_object function. */
2636
2637/* Remember not to use load_object_str in a time-critical situation. */ 2644/* Remember not to use load_object_str in a time-critical situation. */
2638
2639/* Also remember that multiparts objects are not supported for now. */ 2645/* Also remember that multiparts objects are not supported for now. */
2640 2646
2641object * 2647object *
2642load_object_str (const char *obstr) 2648load_object_str (const char *obstr)
2643{ 2649{
2644 object * 2650 object *op;
2645 op;
2646 char
2647 filename[MAX_BUF]; 2651 char filename[MAX_BUF];
2648 2652
2649 sprintf (filename, "%s/cfloadobstr2044", settings.tmpdir); 2653 sprintf (filename, "%s/cfloadobstr2044", settings.tmpdir);
2650 2654
2651 FILE *
2652 tempfile = fopen (filename, "w"); 2655 FILE *tempfile = fopen (filename, "w");
2653 2656
2654 if (tempfile == NULL) 2657 if (tempfile == NULL)
2655 { 2658 {
2656 LOG (llevError, "Error - Unable to access load object temp file\n"); 2659 LOG (llevError, "Error - Unable to access load object temp file\n");
2657 return NULL; 2660 return NULL;
2658 }; 2661 }
2662
2659 fprintf (tempfile, obstr); 2663 fprintf (tempfile, obstr);
2660 fclose (tempfile); 2664 fclose (tempfile);
2661 2665
2662 op = get_object (); 2666 op = get_object ();
2663 2667
2677 * returns NULL if no match. 2681 * returns NULL if no match.
2678 */ 2682 */
2679object * 2683object *
2680find_obj_by_type_subtype (const object *who, int type, int subtype) 2684find_obj_by_type_subtype (const object *who, int type, int subtype)
2681{ 2685{
2682 object * 2686 object *tmp;
2683 tmp;
2684 2687
2685 for (tmp = who->inv; tmp; tmp = tmp->below) 2688 for (tmp = who->inv; tmp; tmp = tmp->below)
2686 if (tmp->type == type && tmp->subtype == subtype) 2689 if (tmp->type == type && tmp->subtype == subtype)
2687 return tmp; 2690 return tmp;
2688 2691
2696 * do the desired thing. 2699 * do the desired thing.
2697 */ 2700 */
2698key_value * 2701key_value *
2699get_ob_key_link (const object *ob, const char *key) 2702get_ob_key_link (const object *ob, const char *key)
2700{ 2703{
2701 key_value * 2704 key_value *link;
2702 link;
2703 2705
2704 for (link = ob->key_values; link != NULL; link = link->next) 2706 for (link = ob->key_values; link != NULL; link = link->next)
2705 {
2706 if (link->key == key) 2707 if (link->key == key)
2707 {
2708 return link; 2708 return link;
2709 }
2710 }
2711 2709
2712 return NULL; 2710 return NULL;
2713} 2711}
2714 2712
2715/* 2713/*
2720 * The returned string is shared. 2718 * The returned string is shared.
2721 */ 2719 */
2722const char * 2720const char *
2723get_ob_key_value (const object *op, const char *const key) 2721get_ob_key_value (const object *op, const char *const key)
2724{ 2722{
2725 key_value * 2723 key_value *link;
2726 link; 2724 shstr_cmp canonical_key (key);
2727 const char *
2728 canonical_key;
2729 2725
2730 canonical_key = shstr::find (key);
2731
2732 if (canonical_key == NULL) 2726 if (!canonical_key)
2733 { 2727 {
2734 /* 1. There being a field named key on any object 2728 /* 1. There being a field named key on any object
2735 * implies there'd be a shared string to find. 2729 * implies there'd be a shared string to find.
2736 * 2. Since there isn't, no object has this field. 2730 * 2. Since there isn't, no object has this field.
2737 * 3. Therefore, *this* object doesn't have this field. 2731 * 3. Therefore, *this* object doesn't have this field.
2738 */ 2732 */
2739 return NULL; 2733 return 0;
2740 } 2734 }
2741 2735
2742 /* This is copied from get_ob_key_link() above - 2736 /* This is copied from get_ob_key_link() above -
2743 * only 4 lines, and saves the function call overhead. 2737 * only 4 lines, and saves the function call overhead.
2744 */ 2738 */
2745 for (link = op->key_values; link != NULL; link = link->next) 2739 for (link = op->key_values; link; link = link->next)
2746 {
2747 if (link->key == canonical_key) 2740 if (link->key == canonical_key)
2748 {
2749 return link->value; 2741 return link->value;
2750 } 2742
2751 }
2752 return NULL; 2743 return 0;
2753} 2744}
2754 2745
2755 2746
2756/* 2747/*
2757 * Updates the canonical_key in op to value. 2748 * Updates the canonical_key in op to value.
2864 } 2855 }
2865 else 2856 else
2866 item = item->env; 2857 item = item->env;
2867} 2858}
2868 2859
2860// return a suitable string describing an objetc in enough detail to find it
2861const char *
2862object::debug_desc (char *info) const
2863{
2864 char info2[256 * 3];
2865 char *p = info;
2866
2867 p += snprintf (p, 256, "%d=\"%s%s%s\"",
2868 count,
2869 &name,
2870 title ? " " : "",
2871 title ? (const char *)title : "");
2872
2873 if (env)
2874 p += snprintf (p, 256, "(in %s)", env->debug_desc (info2));
2875
2876 if (map)
2877 p += snprintf (p, 256, "(on %s@%d+%d)", map->path, x, y);
2878
2879 return info;
2880}
2881
2882const char *
2883object::debug_desc () const
2884{
2885 static char info[256 * 3];
2886 return debug_desc (info);
2887}
2888

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines