ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.c
Revision: 1.6
Committed: Sun Jun 4 19:46:55 2006 UTC (17 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +6 -11 lines
Log Message:
Fix a crash bug that happens with non-euclidean maps: when you end up on
the same map as you started but coordinates haven't change some stupid
useless microptimisation assumed that the coordinates had not changed,
either, leaving them outside the map, leading to an abort().

File Contents

# Content
1 /*
2 * static char *rcsid_object_c =
3 * "$Id$";
4 */
5
6 /*
7 CrossFire, A Multiplayer game for X-windows
8
9 Copyright (C) 2001 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28
29 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
30 sub/add_weight will transcend the environment updating the carrying
31 variable. */
32 #include <global.h>
33 #ifndef WIN32 /* ---win32 exclude headers */
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #endif /* win32 */
38 #include <object.h>
39 #include <funcpoint.h>
40 #include <skills.h>
41 #include <loader.h>
42 #ifdef MEMORY_DEBUG
43 int nroffreeobjects = 0;
44 int nrofallocobjects = 0;
45 #undef OBJ_EXPAND
46 #define OBJ_EXPAND 1
47 #else
48 object objarray[STARTMAX]; /* All objects, allocated this way at first */
49 int nroffreeobjects = STARTMAX; /* How many OBs allocated and free (free) */
50 int nrofallocobjects = STARTMAX; /* How many OBs allocated (free + used) */
51 #endif
52
53 object *objects; /* Pointer to the list of used objects */
54 object *free_objects; /* Pointer to the list of unused objects */
55 object *active_objects; /* List of active objects that need to be processed */
56
57 void (*object_free_callback)(object *ob);
58
59 short freearr_x[SIZEOFFREE]=
60 {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,
61 0,1,2,3,3,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-3,-3,-3,-3,-3,-2,-1};
62 short freearr_y[SIZEOFFREE]=
63 {0,-1,-1,0,1,1,1,0,-1,-2,-2,-2,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,
64 -3,-3,-3,-3,-2,-1,0,1,2,3,3,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-3};
65 int maxfree[SIZEOFFREE]=
66 {0,9,10,13,14,17,18,21,22,25,26,27,30,31,32,33,36,37,39,39,42,43,44,45,
67 48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49};
68 int freedir[SIZEOFFREE]= {
69 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,
70 1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8};
71
72
73 /* Returns TRUE if every key_values in wants has a partner with the same value in has. */
74 static int compare_ob_value_lists_one(const object * wants, const object * has) {
75 key_value * wants_field;
76
77 /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both
78 * objects with lists are rare, and lists stay short. If not, use a
79 * different structure or at least keep the lists sorted...
80 */
81
82 /* For each field in wants, */
83 for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
84 key_value * has_field;
85
86 /* Look for a field in has with the same key. */
87 has_field = get_ob_key_link(has, wants_field->key);
88
89 if (has_field == NULL) {
90 /* No field with that name. */
91 return FALSE;
92 }
93
94 /* Found the matching field. */
95 if (has_field->value != wants_field->value) {
96 /* Values don't match, so this half of the comparison is false. */
97 return FALSE;
98 }
99
100 /* If we get here, we found a match. Now for the next field in wants. */
101 }
102
103 /* If we get here, every field in wants has a matching field in has. */
104 return TRUE;
105 }
106
107 /* Returns TRUE if ob1 has the same key_values as ob2. */
108 static int compare_ob_value_lists(const object * ob1, const object * ob2) {
109 /* However, there may be fields in has which aren't partnered in wants,
110 * so we need to run the comparison *twice*. :(
111 */
112 return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
113 }
114
115 /* Function examines the 2 objects given to it, and returns true if
116 * they can be merged together.
117 *
118 * Note that this function appears a lot longer than the macro it
119 * replaces - this is mostly for clarity - a decent compiler should hopefully
120 * reduce this to the same efficiency.
121 *
122 * Check nrof variable *before* calling CAN_MERGE()
123 *
124 * Improvements made with merge: Better checking on potion, and also
125 * check weight
126 */
127
128 int CAN_MERGE(object *ob1, object *ob2) {
129
130 /* A couple quicksanity checks */
131 if ((ob1 == ob2) || (ob1->type != ob2->type)) return 0;
132
133 if (ob1->speed != ob2->speed) return 0;
134 /* Note sure why the following is the case - either the object has to
135 * be animated or have a very low speed. Is this an attempted monster
136 * check?
137 */
138 if (!QUERY_FLAG(ob1,FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
139 return 0;
140
141 /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
142 * value could not be stored in a sint32 (which unfortunately sometimes is
143 * used to store nrof).
144 */
145 if (ob1->nrof+ob2->nrof >= 1UL<<31)
146 return 0;
147
148 /* This is really a spellbook check - really, we should
149 * check all objects in the inventory.
150 */
151 if (ob1->inv || ob2->inv) {
152 /* if one object has inventory but the other doesn't, not equiv */
153 if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv)) return 0;
154
155 /* Now check to see if the two inventory objects could merge */
156 if (!CAN_MERGE(ob1->inv, ob2->inv)) return 0;
157
158 /* inventory ok - still need to check rest of this object to see
159 * if it is valid.
160 */
161 }
162
163 /* If the objects have been identified, set the BEEN_APPLIED flag.
164 * This is to the comparison of the flags below will be OK. We
165 * just can't ignore the been applied or identified flags, as they
166 * are not equal - just if it has been identified, the been_applied
167 * flags lose any meaning.
168 */
169 if (QUERY_FLAG(ob1, FLAG_IDENTIFIED))
170 SET_FLAG(ob1, FLAG_BEEN_APPLIED);
171
172 if (QUERY_FLAG(ob2, FLAG_IDENTIFIED))
173 SET_FLAG(ob2, FLAG_BEEN_APPLIED);
174
175
176 /* the 0x400000 on flags2 is FLAG_INV_LOCK. I don't think something
177 * being locked in inventory should prevent merging.
178 * 0x4 in flags3 is CLIENT_SENT
179 */
180 if ((ob1->arch != ob2->arch) ||
181 (ob1->flags[0] != ob2->flags[0]) ||
182 (ob1->flags[1] != ob2->flags[1]) ||
183 ((ob1->flags[2] & ~0x400000) != (ob2->flags[2] & ~ 0x400000)) ||
184 ((ob1->flags[3] & ~0x4) != (ob2->flags[3] & ~0x4)) ||
185 (ob1->name != ob2->name) ||
186 (ob1->title != ob2->title) ||
187 (ob1->msg != ob2->msg) ||
188 (ob1->weight != ob2->weight) ||
189 (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist))!=0) ||
190 (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats))!=0) ||
191 (ob1->attacktype != ob2->attacktype) ||
192 (ob1->magic != ob2->magic) ||
193 (ob1->slaying != ob2->slaying) ||
194 (ob1->skill != ob2->skill) ||
195 (ob1->value != ob2->value) ||
196 (ob1->animation_id != ob2->animation_id) ||
197 (ob1->client_type != ob2->client_type) ||
198 (ob1->materialname != ob2->materialname) ||
199 (ob1->lore != ob2->lore) ||
200 (ob1->subtype != ob2->subtype) ||
201 (ob1->move_type != ob2->move_type) ||
202 (ob1->move_block != ob2->move_block) ||
203 (ob1->move_allow != ob2->move_allow) ||
204 (ob1->move_on != ob2->move_on) ||
205 (ob1->move_off != ob2->move_off) ||
206 (ob1->move_slow != ob2->move_slow) ||
207 (ob1->move_slow_penalty != ob2->move_slow_penalty)
208 )
209 return 0;
210
211 /* Don't merge objects that are applied. With the new 'body' code,
212 * it is possible for most any character to have more than one of
213 * some items equipped, and we don't want those to merge.
214 */
215 if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
216 return 0;
217
218 switch (ob1->type) {
219 case SCROLL:
220 if (ob1->level != ob2->level) return 0;
221 break;
222
223 }
224 if (ob1->key_values != NULL || ob2->key_values != NULL) {
225 /* At least one of these has key_values. */
226 if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
227 /* One has fields, but the other one doesn't. */
228 return 0;
229 } else if (!compare_ob_value_lists(ob1, ob2)) {
230 return 0;
231 }
232 }
233
234 /* Everything passes, must be OK. */
235 return 1;
236 }
237
238 /*
239 * sum_weight() is a recursive function which calculates the weight
240 * an object is carrying. It goes through in figures out how much
241 * containers are carrying, and sums it up.
242 */
243 signed long sum_weight(object *op) {
244 signed long sum;
245 object *inv;
246 for(sum = 0, inv = op->inv; inv != NULL; inv = inv->below) {
247 if (inv->inv)
248 sum_weight(inv);
249 sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1);
250 }
251 if (op->type == CONTAINER && op->stats.Str)
252 sum = (sum * (100 - op->stats.Str))/100;
253 if(op->carrying != sum)
254 op->carrying = sum;
255 return sum;
256 }
257
258 /**
259 * Return the outermost environment object for a given object.
260 */
261
262 object *object_get_env_recursive (object *op) {
263 while (op->env != NULL)
264 op = op->env;
265 return op;
266 }
267
268 /*
269 * Eneq(@csd.uu.se): Since we can have items buried in a character we need
270 * a better check. We basically keeping traversing up until we can't
271 * or find a player.
272 */
273
274 object *is_player_inv (object *op) {
275 for (;op!=NULL&&op->type!=PLAYER; op=op->env)
276 if (op->env==op)
277 op->env = NULL;
278 return op;
279 }
280
281 /*
282 * Used by: Crossedit: dump. Server DM commands: dumpbelow, dump.
283 * Some error messages.
284 * The result of the dump is stored in the static global errmsg array.
285 */
286
287 void dump_object2(object *op) {
288 char *cp;
289 /* object *tmp;*/
290
291 if(op->arch!=NULL) {
292 strcat(errmsg,"arch ");
293 strcat(errmsg,op->arch->name?op->arch->name:"(null)");
294 strcat(errmsg,"\n");
295 if((cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
296 strcat(errmsg,cp);
297 #if 0
298 /* Don't dump player diffs - they are too long, mostly meaningless, and
299 * will overflow the buffer.
300 * Changed so that we don't dump inventory either. This may
301 * also overflow the buffer.
302 */
303 if(op->type!=PLAYER && (cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
304 strcat(errmsg,cp);
305 for (tmp=op->inv; tmp; tmp=tmp->below)
306 dump_object2(tmp);
307 #endif
308 strcat(errmsg,"end\n");
309 } else {
310 strcat(errmsg,"Object ");
311 if (op->name==NULL) strcat(errmsg, "(null)");
312 else strcat(errmsg,op->name);
313 strcat(errmsg,"\n");
314 #if 0
315 if((cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
316 strcat(errmsg,cp);
317 for (tmp=op->inv; tmp; tmp=tmp->below)
318 dump_object2(tmp);
319 #endif
320 strcat(errmsg,"end\n");
321 }
322 }
323
324 /*
325 * Dumps an object. Returns output in the static global errmsg array.
326 */
327
328 void dump_object(object *op) {
329 if(op==NULL) {
330 strcpy(errmsg,"[NULL pointer]");
331 return;
332 }
333 errmsg[0]='\0';
334 dump_object2(op);
335 }
336
337 /* GROS - Dumps an object. Return the result into a string */
338 /* Note that no checking is done for the validity of the target string, so */
339 /* you need to be sure that you allocated enough space for it. */
340 void dump_me(object *op, char *outstr)
341 {
342 char *cp;
343
344 if(op==NULL)
345 {
346 strcpy(outstr,"[NULL pointer]");
347 return;
348 }
349 outstr[0]='\0';
350
351 if(op->arch!=NULL)
352 {
353 strcat(outstr,"arch ");
354 strcat(outstr,op->arch->name?op->arch->name:"(null)");
355 strcat(outstr,"\n");
356 if((cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
357 strcat(outstr,cp);
358 strcat(outstr,"end\n");
359 }
360 else
361 {
362 strcat(outstr,"Object ");
363 if (op->name==NULL)
364 strcat(outstr, "(null)");
365 else
366 strcat(outstr,op->name);
367 strcat(outstr,"\n");
368 strcat(outstr,"end\n");
369 }
370 }
371
372 /*
373 * This is really verbose...Can be triggered by the P key while in DM mode.
374 * All objects are dumped to stderr (or alternate logfile, if in server-mode)
375 */
376
377 void dump_all_objects(void) {
378 object *op;
379 for(op=objects;op!=NULL;op=op->next) {
380 dump_object(op);
381 fprintf(logfile, "Object %d\n:%s\n", op->count, errmsg);
382 }
383 }
384
385 /*
386 * get_nearest_part(multi-object, object 2) returns the part of the
387 * multi-object 1 which is closest to the second object.
388 * If it's not a multi-object, it is returned.
389 */
390
391 object *get_nearest_part(object *op, const object *pl) {
392 object *tmp,*closest;
393 int last_dist,i;
394 if(op->more==NULL)
395 return op;
396 for(last_dist=distance(op,pl),closest=op,tmp=op->more;tmp!=NULL;tmp=tmp->more)
397 if((i=distance(tmp,pl))<last_dist)
398 closest=tmp,last_dist=i;
399 return closest;
400 }
401
402 /*
403 * Returns the object which has the count-variable equal to the argument.
404 */
405
406 object *find_object(tag_t i) {
407 object *op;
408 for(op=objects;op!=NULL;op=op->next)
409 if(op->count==i)
410 break;
411 return op;
412 }
413
414 /*
415 * Returns the first object which has a name equal to the argument.
416 * Used only by the patch command, but not all that useful.
417 * Enables features like "patch <name-of-other-player> food 999"
418 */
419
420 object *find_object_name(const char *str) {
421 const char *name=add_string(str);
422 object *op;
423 for(op=objects;op!=NULL;op=op->next)
424 if(op->name==name)
425 break;
426 free_string(name);
427 return op;
428 }
429
430 void free_all_object_data(void) {
431 #ifdef MEMORY_DEBUG
432 object *op, *next;
433
434 for (op=free_objects; op!=NULL; ) {
435 next=op->next;
436 free(op);
437 nrofallocobjects--;
438 nroffreeobjects--;
439 op=next;
440 }
441 #endif
442 LOG(llevDebug,"%d allocated objects, %d free objects, STARMAX=%d\n",
443 nrofallocobjects, nroffreeobjects,STARTMAX);
444 }
445
446 /*
447 * Returns the object which this object marks as being the owner.
448 * A id-scheme is used to avoid pointing to objects which have been
449 * freed and are now reused. If this is detected, the owner is
450 * set to NULL, and NULL is returned.
451 * Changed 2004-02-12 - if the player is setting at the play again
452 * prompt, he is removed, and we don't want to treat him as an owner of
453 * anything, so check removed flag. I don't expect that this should break
454 * anything - once an object is removed, it is basically dead anyways.
455 */
456
457 object *get_owner(object *op) {
458 if(op->owner==NULL)
459 return NULL;
460
461 if (!QUERY_FLAG(op->owner,FLAG_FREED) && !QUERY_FLAG(op->owner, FLAG_REMOVED) &&
462 op->owner->count==op->ownercount)
463 return op->owner;
464
465 op->owner=NULL;
466 op->ownercount=0;
467 return NULL;
468 }
469
470 void clear_owner(object *op)
471 {
472 if (!op) return;
473
474 if (op->owner && op->ownercount == op->owner->count)
475 op->owner->refcount--;
476
477 op->owner = NULL;
478 op->ownercount = 0;
479 }
480
481
482
483 /*
484 * Sets the owner and sets the skill and exp pointers to owner's current
485 * skill and experience objects.
486 */
487 void set_owner (object *op, object *owner)
488 {
489 if(owner==NULL||op==NULL)
490 return;
491
492 /* next line added to allow objects which own objects */
493 /* Add a check for ownercounts in here, as I got into an endless loop
494 * with the fireball owning a poison cloud which then owned the
495 * fireball. I believe that was caused by one of the objects getting
496 * freed and then another object replacing it. Since the ownercounts
497 * didn't match, this check is valid and I believe that cause is valid.
498 */
499 while (owner->owner && owner!=owner->owner &&
500 owner->ownercount==owner->owner->count) owner=owner->owner;
501
502 /* IF the owner still has an owner, we did not resolve to a final owner.
503 * so lets not add to that.
504 */
505 if (owner->owner) return;
506
507 op->owner=owner;
508
509 op->ownercount=owner->count;
510 owner->refcount++;
511
512 }
513
514 /* Set the owner to clone's current owner and set the skill and experience
515 * objects to clone's objects (typically those objects that where the owner's
516 * current skill and experience objects at the time when clone's owner was
517 * set - not the owner's current skill and experience objects).
518 *
519 * Use this function if player created an object (e.g. fire bullet, swarm
520 * spell), and this object creates further objects whose kills should be
521 * accounted for the player's original skill, even if player has changed
522 * skills meanwhile.
523 */
524 void copy_owner (object *op, object *clone)
525 {
526 object *owner = get_owner (clone);
527 if (owner == NULL) {
528 /* players don't have owners - they own themselves. Update
529 * as appropriate.
530 */
531 if (clone->type == PLAYER) owner=clone;
532 else return;
533 }
534 set_owner(op, owner);
535
536 }
537
538 /*
539 * Resets vital variables in an object
540 */
541
542 void reset_object(object *op) {
543
544 op->name = NULL;
545 op->name_pl = NULL;
546 op->title = NULL;
547 op->race = NULL;
548 op->slaying = NULL;
549 op->skill = NULL;
550 op->msg = NULL;
551 op->materialname = NULL;
552 op->lore = NULL;
553 op->current_weapon_script = NULL;
554 clear_object(op);
555 }
556
557 /* Zero the key_values on op, decrementing the shared-string
558 * refcounts and freeing the links.
559 */
560 static void free_key_values(object * op) {
561 key_value * i;
562 key_value * next = NULL;
563
564 if (op->key_values == NULL) return;
565
566 for (i = op->key_values; i != NULL; i = next) {
567 /* Store next *first*. */
568 next = i->next;
569
570 if (i->key) FREE_AND_CLEAR_STR(i->key);
571 if (i->value) FREE_AND_CLEAR_STR(i->value);
572 i->next = NULL;
573 free(i);
574 }
575
576 op->key_values = NULL;
577 }
578
579
580 /*
581 * clear_object() frees everything allocated by an object, and also
582 * clears all variables and flags to default settings.
583 */
584
585 void clear_object(object *op) {
586
587 event *evt;
588 event *evt2;
589
590 /* redo this to be simpler/more efficient. Was also seeing
591 * crashes in the old code. Move this to the top - am
592 * seeing periodic crashes in this code, and would like to have
593 * as much info available as possible (eg, object name).
594 */
595 for (evt = op->events; evt; evt=evt2) {
596 evt2 = evt->next;
597
598 if (evt->hook != NULL) FREE_AND_CLEAR_STR(evt->hook);
599 if (evt->plugin != NULL) FREE_AND_CLEAR_STR(evt->plugin);
600 if (evt->options != NULL) FREE_AND_CLEAR_STR(evt->options);
601
602 free(evt);
603 }
604 op->events = NULL;
605
606 free_key_values(op);
607
608 /* the memset will clear all these values for us, but we need
609 * to reduce the refcount on them.
610 */
611 if (op->name!=NULL) FREE_AND_CLEAR_STR(op->name);
612 if (op->name_pl!=NULL) FREE_AND_CLEAR_STR(op->name_pl);
613 if (op->title != NULL) FREE_AND_CLEAR_STR(op->title);
614 if (op->race!=NULL) FREE_AND_CLEAR_STR(op->race);
615 if (op->slaying!=NULL) FREE_AND_CLEAR_STR(op->slaying);
616 if (op->skill!=NULL) FREE_AND_CLEAR_STR(op->skill);
617 if (op->msg!=NULL) FREE_AND_CLEAR_STR(op->msg);
618 if (op->lore!=NULL) FREE_AND_CLEAR_STR(op->lore);
619 if (op->materialname!= NULL) FREE_AND_CLEAR_STR(op->materialname);
620
621
622 memset((void*)((char*)op + offsetof(object, name)),
623 0, sizeof(object)-offsetof(object, name));
624 /* Below here, we clear things that are not done by the memset,
625 * or set default values that are not zero.
626 */
627 /* This is more or less true */
628 SET_FLAG(op, FLAG_REMOVED);
629
630
631 op->contr = NULL;
632 op->below=NULL;
633 op->above=NULL;
634 op->inv=NULL;
635 op->events=NULL;
636 op->container=NULL;
637 op->env=NULL;
638 op->more=NULL;
639 op->head=NULL;
640 op->map=NULL;
641 op->refcount=0;
642 op->active_next = NULL;
643 op->active_prev = NULL;
644 /* What is not cleared is next, prev, and count */
645
646 op->expmul=1.0;
647 op->face = blank_face;
648 op->attacked_by_count= -1;
649 if (settings.casting_time)
650 op->casting_time = -1;
651
652 }
653
654 /*
655 * copy object first frees everything allocated by the second object,
656 * and then copies the contends of the first object into the second
657 * object, allocating what needs to be allocated. Basically, any
658 * data that is malloc'd needs to be re-malloc/copied. Otherwise,
659 * if the first object is freed, the pointers in the new object
660 * will point at garbage.
661 */
662
663 void copy_object(object *op2, object *op) {
664 int is_freed=QUERY_FLAG(op,FLAG_FREED),is_removed=QUERY_FLAG(op,FLAG_REMOVED);
665 event *evt, *evt2, *evt_new;
666
667 /* Decrement the refcounts, but don't bother zeroing the fields;
668 they'll be overwritten by memcpy. */
669 if(op->name!=NULL) free_string(op->name);
670 if(op->name_pl!=NULL) free_string(op->name_pl);
671 if(op->title!=NULL) free_string(op->title);
672 if(op->race!=NULL) free_string(op->race);
673 if(op->slaying!=NULL) free_string(op->slaying);
674 if(op->skill!=NULL) free_string(op->skill);
675 if(op->msg!=NULL) free_string(op->msg);
676 if(op->lore!=NULL) free_string(op->lore);
677 if(op->materialname != NULL) free_string(op->materialname);
678 if(op->custom_name != NULL) free_string(op->custom_name);
679
680 /* Basically, same code as from clear_object() */
681 for (evt = op->events; evt; evt=evt2) {
682 evt2 = evt->next;
683
684 if (evt->hook != NULL) FREE_AND_CLEAR_STR(evt->hook);
685 if (evt->plugin != NULL) FREE_AND_CLEAR_STR(evt->plugin);
686 if (evt->options != NULL) FREE_AND_CLEAR_STR(evt->options);
687
688 free(evt);
689 }
690 op->events = NULL;
691
692 free_key_values(op);
693
694 /* op is the destination, op2 is the source. */
695 (void) memcpy((void *)((char *) op +offsetof(object,name)),
696 (void *)((char *) op2+offsetof(object,name)),
697 sizeof(object)-offsetof(object, name));
698
699 if(is_freed) SET_FLAG(op,FLAG_FREED);
700 if(is_removed) SET_FLAG(op,FLAG_REMOVED);
701 if(op->name!=NULL) add_refcount(op->name);
702 if(op->name_pl!=NULL) add_refcount(op->name_pl);
703 if(op->title!=NULL) add_refcount(op->title);
704 if(op->race!=NULL) add_refcount(op->race);
705 if(op->slaying!=NULL) add_refcount(op->slaying);
706 if(op->skill!=NULL) add_refcount(op->skill);
707 if(op->lore!=NULL) add_refcount(op->lore);
708 if(op->msg!=NULL) add_refcount(op->msg);
709 if(op->custom_name!=NULL) add_refcount(op->custom_name);
710 if (op->materialname != NULL) add_refcount(op->materialname);
711
712 if((op2->speed<0) && !editor)
713 op->speed_left=op2->speed_left-RANDOM()%200/100.0;
714
715 /* Copy over event information */
716 evt2 = NULL;
717 for (evt = op2->events; evt; evt=evt->next) {
718 evt_new = malloc(sizeof(event));
719 memcpy(evt_new, evt, sizeof(event));
720 if (evt_new->hook) add_refcount(evt_new->hook);
721 if (evt_new->plugin) add_refcount(evt_new->plugin);
722 if (evt_new->options) add_refcount(evt_new->options);
723 evt_new->next = NULL;
724
725 /* Try to be a little clever here, and store away the
726 * last event we copied, so that its simpler to update the
727 * pointer.
728 */
729 if (evt2)
730 evt2->next = evt_new;
731 else
732 op->events = evt_new;
733
734 evt2 = evt_new;
735 }
736 /* Copy over key_values, if any. */
737 if (op2->key_values != NULL) {
738 key_value * tail = NULL;
739 key_value * i;
740
741 op->key_values = NULL;
742
743 for (i = op2->key_values; i != NULL; i = i->next) {
744 key_value * new_link = malloc(sizeof(key_value));
745
746 new_link->next = NULL;
747 new_link->key = add_refcount(i->key);
748 if (i->value)
749 new_link->value = add_refcount(i->value);
750 else
751 new_link->value = NULL;
752
753 /* Try and be clever here, too. */
754 if (op->key_values == NULL) {
755 op->key_values = new_link;
756 tail = new_link;
757 } else {
758 tail->next = new_link;
759 tail = new_link;
760 }
761 }
762 }
763
764 update_ob_speed(op);
765 }
766
767 /*
768 * expand_objects() allocates more objects for the list of unused objects.
769 * It is called from get_object() if the unused list is empty.
770 */
771
772 void expand_objects(void) {
773 int i;
774 object *new;
775 new = (object *) CALLOC(OBJ_EXPAND,sizeof(object));
776
777 if(new==NULL)
778 fatal(OUT_OF_MEMORY);
779 free_objects=new;
780 new[0].prev=NULL;
781 new[0].next= &new[1],
782 SET_FLAG(&(new[0]), FLAG_REMOVED);
783 SET_FLAG(&(new[0]), FLAG_FREED);
784
785 for(i=1;i<OBJ_EXPAND-1;i++) {
786 new[i].next= &new[i+1],
787 new[i].prev= &new[i-1],
788 SET_FLAG(&(new[i]), FLAG_REMOVED);
789 SET_FLAG(&(new[i]), FLAG_FREED);
790 }
791 new[OBJ_EXPAND-1].prev= &new[OBJ_EXPAND-2],
792 new[OBJ_EXPAND-1].next=NULL,
793 SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_REMOVED);
794 SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_FREED);
795
796 nrofallocobjects += OBJ_EXPAND;
797 nroffreeobjects += OBJ_EXPAND;
798 }
799
800 /*
801 * get_object() grabs an object from the list of unused objects, makes
802 * sure it is initialised, and returns it.
803 * If there are no free objects, expand_objects() is called to get more.
804 */
805
806 object *get_object(void) {
807 object *op;
808
809 if(free_objects==NULL) {
810 expand_objects();
811 }
812 op=free_objects;
813 #ifdef MEMORY_DEBUG
814 /* The idea is hopefully by doing a realloc, the memory
815 * debugging program will now use the current stack trace to
816 * report leaks.
817 */
818 op = realloc(op, sizeof(object));
819 SET_FLAG(op, FLAG_REMOVED);
820 SET_FLAG(op, FLAG_FREED);
821 #endif
822
823 if(!QUERY_FLAG(op,FLAG_FREED)) {
824 LOG(llevError,"Fatal: Getting busy object.\n");
825 }
826 free_objects=op->next;
827 if(free_objects!=NULL)
828 free_objects->prev=NULL;
829 op->count= ++ob_count;
830 op->name=NULL;
831 op->name_pl=NULL;
832 op->title=NULL;
833 op->race=NULL;
834 op->slaying=NULL;
835 op->skill = NULL;
836 op->lore=NULL;
837 op->msg=NULL;
838 op->materialname=NULL;
839 op->next=objects;
840 op->prev=NULL;
841 op->active_next = NULL;
842 op->active_prev = NULL;
843 if(objects!=NULL)
844 objects->prev=op;
845 objects=op;
846 clear_object(op);
847 SET_FLAG(op,FLAG_REMOVED);
848 nroffreeobjects--;
849 return op;
850 }
851
852 /*
853 * If an object with the IS_TURNABLE() flag needs to be turned due
854 * to the closest player being on the other side, this function can
855 * be called to update the face variable, _and_ how it looks on the map.
856 */
857
858 void update_turn_face(object *op) {
859 if(!QUERY_FLAG(op,FLAG_IS_TURNABLE)||op->arch==NULL)
860 return;
861 SET_ANIMATION(op, op->direction);
862 update_object(op,UP_OBJ_FACE);
863 }
864
865 /*
866 * Updates the speed of an object. If the speed changes from 0 to another
867 * value, or vice versa, then add/remove the object from the active list.
868 * This function needs to be called whenever the speed of an object changes.
869 */
870
871 void update_ob_speed(object *op) {
872 extern int arch_init;
873
874 /* No reason putting the archetypes objects on the speed list,
875 * since they never really need to be updated.
876 */
877
878 if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
879 LOG(llevError,"Object %s is freed but has speed.\n", op->name);
880 #ifdef MANY_CORES
881 abort();
882 #else
883 op->speed = 0;
884 #endif
885 }
886 if (arch_init) {
887 return;
888 }
889 if (FABS(op->speed)>MIN_ACTIVE_SPEED) {
890 /* If already on active list, don't do anything */
891 if (op->active_next || op->active_prev || op==active_objects)
892 return;
893
894 /* process_events() expects us to insert the object at the beginning
895 * of the list. */
896 op->active_next = active_objects;
897 if (op->active_next!=NULL)
898 op->active_next->active_prev = op;
899 active_objects = op;
900 }
901 else {
902 /* If not on the active list, nothing needs to be done */
903 if (!op->active_next && !op->active_prev && op!=active_objects)
904 return;
905
906 if (op->active_prev==NULL) {
907 active_objects = op->active_next;
908 if (op->active_next!=NULL)
909 op->active_next->active_prev = NULL;
910 }
911 else {
912 op->active_prev->active_next = op->active_next;
913 if (op->active_next)
914 op->active_next->active_prev = op->active_prev;
915 }
916 op->active_next = NULL;
917 op->active_prev = NULL;
918 }
919 }
920
921 /* This function removes object 'op' from the list of active
922 * objects.
923 * This should only be used for style maps or other such
924 * reference maps where you don't want an object that isn't
925 * in play chewing up cpu time getting processed.
926 * The reverse of this is to call update_ob_speed, which
927 * will do the right thing based on the speed of the object.
928 */
929 void remove_from_active_list(object *op)
930 {
931 /* If not on the active list, nothing needs to be done */
932 if (!op->active_next && !op->active_prev && op!=active_objects)
933 return;
934
935 if (op->active_prev==NULL) {
936 active_objects = op->active_next;
937 if (op->active_next!=NULL)
938 op->active_next->active_prev = NULL;
939 }
940 else {
941 op->active_prev->active_next = op->active_next;
942 if (op->active_next)
943 op->active_next->active_prev = op->active_prev;
944 }
945 op->active_next = NULL;
946 op->active_prev = NULL;
947 }
948
949 /*
950 * update_object() updates the array which represents the map.
951 * It takes into account invisible objects (and represent squares covered
952 * by invisible objects by whatever is below them (unless it's another
953 * invisible object, etc...)
954 * If the object being updated is beneath a player, the look-window
955 * of that player is updated (this might be a suboptimal way of
956 * updating that window, though, since update_object() is called _often_)
957 *
958 * action is a hint of what the caller believes need to be done.
959 * For example, if the only thing that has changed is the face (due to
960 * an animation), we don't need to call update_position until that actually
961 * comes into view of a player. OTOH, many other things, like addition/removal
962 * of walls or living creatures may need us to update the flags now.
963 * current action are:
964 * UP_OBJ_INSERT: op was inserted
965 * UP_OBJ_REMOVE: op was removed
966 * UP_OBJ_CHANGE: object has somehow changed. In this case, we always update
967 * as that is easier than trying to look at what may have changed.
968 * UP_OBJ_FACE: only the objects face has changed.
969 */
970
971 void update_object(object *op, int action) {
972 int update_now=0, flags;
973 MoveType move_on, move_off, move_block, move_slow;
974
975 if (op == NULL) {
976 /* this should never happen */
977 LOG(llevDebug,"update_object() called for NULL object.\n");
978 return;
979 }
980
981 if(op->env!=NULL) {
982 /* Animation is currently handled by client, so nothing
983 * to do in this case.
984 */
985 return;
986 }
987
988 /* If the map is saving, don't do anything as everything is
989 * going to get freed anyways.
990 */
991 if (!op->map || op->map->in_memory == MAP_SAVING) return;
992
993 /* make sure the object is within map boundaries */
994 if (op->x < 0 || op->x >= MAP_WIDTH(op->map) ||
995 op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
996 LOG(llevError,"update_object() called for object out of map!\n");
997 #ifdef MANY_CORES
998 abort();
999 #endif
1000 return;
1001 }
1002
1003 flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1004 SET_MAP_FLAGS(op->map, op->x, op->y, flags | P_NEED_UPDATE);
1005 move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1006 move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1007 move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1008 move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1009
1010 if (action == UP_OBJ_INSERT) {
1011 if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) && !(flags & P_BLOCKSVIEW))
1012 update_now=1;
1013
1014 if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags & P_NO_MAGIC))
1015 update_now=1;
1016
1017 if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags & P_NO_CLERIC))
1018 update_now=1;
1019
1020 if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE))
1021 update_now=1;
1022
1023 if ((move_on | op->move_on) != move_on) update_now=1;
1024 if ((move_off | op->move_off) != move_off) update_now=1;
1025 /* This isn't perfect, but I don't expect a lot of objects to
1026 * to have move_allow right now.
1027 */
1028 if (((move_block | op->move_block) & ~op->move_allow) != move_block)
1029 update_now=1;
1030 if ((move_slow | op->move_slow) != move_slow) update_now=1;
1031 }
1032 /* if the object is being removed, we can't make intelligent
1033 * decisions, because remove_ob can't really pass the object
1034 * that is being removed.
1035 */
1036 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) {
1037 update_now=1;
1038 } else if (action == UP_OBJ_FACE) {
1039 /* Nothing to do for that case */
1040 }
1041 else {
1042 LOG(llevError,"update_object called with invalid action: %d\n", action);
1043 }
1044
1045 if (update_now) {
1046 SET_MAP_FLAGS(op->map, op->x, op->y, flags | P_NO_ERROR | P_NEED_UPDATE);
1047 update_position(op->map, op->x, op->y);
1048 }
1049
1050 if(op->more!=NULL)
1051 update_object(op->more, action);
1052 }
1053
1054
1055 /*
1056 * free_object() frees everything allocated by an object, removes
1057 * it from the list of used objects, and puts it on the list of
1058 * free objects. The IS_FREED() flag is set in the object.
1059 * The object must have been removed by remove_ob() first for
1060 * this function to succeed.
1061 *
1062 * If free_inventory is set, free inventory as well. Else drop items in
1063 * inventory to the ground.
1064 */
1065
1066 void free_object(object *ob) {
1067 free_object2(ob, 0);
1068 }
1069 void free_object2(object *ob, int free_inventory) {
1070 object *tmp,*op;
1071
1072 if (object_free_callback)
1073 object_free_callback (ob);
1074
1075 if (!QUERY_FLAG(ob,FLAG_REMOVED)) {
1076 LOG(llevDebug,"Free object called with non removed object\n");
1077 dump_object(ob);
1078 #ifdef MANY_CORES
1079 abort();
1080 #endif
1081 }
1082 if(QUERY_FLAG(ob,FLAG_FRIENDLY)) {
1083 LOG(llevMonster,"Warning: tried to free friendly object.\n");
1084 remove_friendly_object(ob);
1085 }
1086 if(QUERY_FLAG(ob,FLAG_FREED)) {
1087 dump_object(ob);
1088 LOG(llevError,"Trying to free freed object.\n%s\n",errmsg);
1089 return;
1090 }
1091 if(ob->more!=NULL) {
1092 free_object2(ob->more, free_inventory);
1093 ob->more=NULL;
1094 }
1095 if (ob->inv) {
1096 /* Only if the space blocks everything do we not process -
1097 * if some form of movemnt is allowed, let objects
1098 * drop on that space.
1099 */
1100 if (free_inventory || ob->map==NULL || ob->map->in_memory!=MAP_IN_MEMORY ||
1101 (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL))
1102 {
1103 op=ob->inv;
1104 while(op!=NULL) {
1105 tmp=op->below;
1106 remove_ob(op);
1107 free_object2(op, free_inventory);
1108 op=tmp;
1109 }
1110 }
1111 else { /* Put objects in inventory onto this space */
1112 op=ob->inv;
1113 while(op!=NULL) {
1114 tmp=op->below;
1115 remove_ob(op);
1116 if(QUERY_FLAG(op,FLAG_STARTEQUIP)||QUERY_FLAG(op,FLAG_NO_DROP) ||
1117 op->type==RUNE || op->type==TRAP || QUERY_FLAG(op,FLAG_IS_A_TEMPLATE))
1118 free_object(op);
1119 else {
1120 op->x=ob->x;
1121 op->y=ob->y;
1122 insert_ob_in_map(op,ob->map,NULL,0); /* Insert in same map as the envir */
1123 }
1124 op=tmp;
1125 }
1126 }
1127 }
1128 /* Remove object from the active list */
1129 ob->speed = 0;
1130 update_ob_speed(ob);
1131
1132 SET_FLAG(ob, FLAG_FREED);
1133 ob->count = 0;
1134
1135 /* Remove this object from the list of used objects */
1136 if(ob->prev==NULL) {
1137 objects=ob->next;
1138 if(objects!=NULL)
1139 objects->prev=NULL;
1140 }
1141 else {
1142 ob->prev->next=ob->next;
1143 if(ob->next!=NULL)
1144 ob->next->prev=ob->prev;
1145 }
1146
1147 if(ob->name!=NULL) FREE_AND_CLEAR_STR(ob->name);
1148 if(ob->name_pl!=NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1149 if(ob->title!=NULL) FREE_AND_CLEAR_STR(ob->title);
1150 if(ob->race!=NULL) FREE_AND_CLEAR_STR(ob->race);
1151 if(ob->slaying!=NULL) FREE_AND_CLEAR_STR(ob->slaying);
1152 if(ob->skill!=NULL) FREE_AND_CLEAR_STR(ob->skill);
1153 if(ob->lore!=NULL) FREE_AND_CLEAR_STR(ob->lore);
1154 if(ob->msg!=NULL) FREE_AND_CLEAR_STR(ob->msg);
1155 if(ob->materialname!=NULL) FREE_AND_CLEAR_STR(ob->materialname);
1156
1157
1158 /* Why aren't events freed? */
1159 free_key_values(ob);
1160
1161 #if 0 /* MEMORY_DEBUG*/
1162 /* This is a nice idea. Unfortunately, a lot of the code in crossfire
1163 * presumes the freed_object will stick around for at least a little
1164 * bit
1165 */
1166 /* this is necessary so that memory debugging programs will
1167 * be able to accurately report source of malloc. If we recycle
1168 * objects, then some other area may be doing the get_object
1169 * and not freeing it, but the original one that malloc'd the
1170 * object will get the blame.
1171 */
1172 free(ob);
1173 #else
1174
1175 /* Now link it with the free_objects list: */
1176 ob->prev=NULL;
1177 ob->next=free_objects;
1178 if(free_objects!=NULL)
1179 free_objects->prev=ob;
1180 free_objects=ob;
1181 nroffreeobjects++;
1182 #endif
1183 }
1184
1185 /*
1186 * count_free() returns the number of objects on the list of free objects.
1187 */
1188
1189 int count_free(void) {
1190 int i=0;
1191 object *tmp=free_objects;
1192 while(tmp!=NULL)
1193 tmp=tmp->next, i++;
1194 return i;
1195 }
1196
1197 /*
1198 * count_used() returns the number of objects on the list of used objects.
1199 */
1200
1201 int count_used(void) {
1202 int i=0;
1203 object *tmp=objects;
1204 while(tmp!=NULL)
1205 tmp=tmp->next, i++;
1206 return i;
1207 }
1208
1209 /*
1210 * count_active() returns the number of objects on the list of active objects.
1211 */
1212
1213 int count_active(void) {
1214 int i=0;
1215 object *tmp=active_objects;
1216 while(tmp!=NULL)
1217 tmp=tmp->active_next, i++;
1218 return i;
1219 }
1220
1221 /*
1222 * sub_weight() recursively (outwards) subtracts a number from the
1223 * weight of an object (and what is carried by it's environment(s)).
1224 */
1225
1226 void sub_weight (object *op, signed long weight) {
1227 while (op != NULL) {
1228 if (op->type == CONTAINER) {
1229 weight=(signed long)(weight*(100-op->stats.Str)/100);
1230 }
1231 op->carrying-=weight;
1232 op = op->env;
1233 }
1234 }
1235
1236 /* remove_ob(op):
1237 * This function removes the object op from the linked list of objects
1238 * which it is currently tied to. When this function is done, the
1239 * object will have no environment. If the object previously had an
1240 * environment, the x and y coordinates will be updated to
1241 * the previous environment.
1242 * Beware: This function is called from the editor as well!
1243 */
1244
1245 void remove_ob(object *op) {
1246 object *tmp,*last=NULL;
1247 object *otmp;
1248 tag_t tag;
1249 int check_walk_off;
1250 mapstruct *m;
1251 sint16 x,y;
1252
1253
1254 if(QUERY_FLAG(op,FLAG_REMOVED)) {
1255 dump_object(op);
1256 LOG(llevError,"Trying to remove removed object.\n%s\n",errmsg);
1257
1258 /* Changed it to always dump core in this case. As has been learned
1259 * in the past, trying to recover from errors almost always
1260 * make things worse, and this is a real error here - something
1261 * that should not happen.
1262 * Yes, if this was a mission critical app, trying to do something
1263 * to recover may make sense, but that is because failure of the app
1264 * may have other disastrous problems. Cf runs out of a script
1265 * so is easily enough restarted without any real problems.
1266 * MSW 2001-07-01
1267 */
1268 abort();
1269 }
1270 if(op->more!=NULL)
1271 remove_ob(op->more);
1272
1273 SET_FLAG(op, FLAG_REMOVED);
1274
1275 /*
1276 * In this case, the object to be removed is in someones
1277 * inventory.
1278 */
1279 if(op->env!=NULL) {
1280 if(op->nrof)
1281 sub_weight(op->env, op->weight*op->nrof);
1282 else
1283 sub_weight(op->env, op->weight+op->carrying);
1284
1285 /* NO_FIX_PLAYER is set when a great many changes are being
1286 * made to players inventory. If set, avoiding the call
1287 * to save cpu time.
1288 */
1289 if ((otmp=is_player_inv(op->env))!=NULL && otmp->contr &&
1290 !QUERY_FLAG(otmp,FLAG_NO_FIX_PLAYER))
1291 fix_player(otmp);
1292
1293 if(op->above!=NULL)
1294 op->above->below=op->below;
1295 else
1296 op->env->inv=op->below;
1297
1298 if(op->below!=NULL)
1299 op->below->above=op->above;
1300
1301 /* we set up values so that it could be inserted into
1302 * the map, but we don't actually do that - it is up
1303 * to the caller to decide what we want to do.
1304 */
1305 op->x=op->env->x,op->y=op->env->y;
1306 op->ox=op->x,op->oy=op->y;
1307 op->map=op->env->map;
1308 op->above=NULL,op->below=NULL;
1309 op->env=NULL;
1310 return;
1311 }
1312
1313 /* If we get here, we are removing it from a map */
1314 if (op->map == NULL) return;
1315
1316 x = op->x;
1317 y = op->y;
1318 m = get_map_from_coord(op->map, &x, &y);
1319
1320 if (!m) {
1321 LOG(llevError,"remove_ob called when object was on map but appears to not be within valid coordinates? %s (%d,%d)\n",
1322 op->map->path, op->x, op->y);
1323 /* in old days, we used to set x and y to 0 and continue.
1324 * it seems if we get into this case, something is probablye
1325 * screwed up and should be fixed.
1326 */
1327 abort();
1328 }
1329 if (op->map != m) {
1330 LOG(llevDebug,"remove_ob: Object not really on map it claimed to be on? %s != %s, %d,%d != %d,%d\n",
1331 op->map->path, m->path, op->x, op->y, x, y);
1332 }
1333
1334 /* Re did the following section of code - it looks like it had
1335 * lots of logic for things we no longer care about
1336 */
1337
1338 /* link the object above us */
1339 if (op->above)
1340 op->above->below=op->below;
1341 else
1342 SET_MAP_TOP(m,x,y,op->below); /* we were top, set new top */
1343
1344 /* Relink the object below us, if there is one */
1345 if(op->below) {
1346 op->below->above=op->above;
1347 } else {
1348 /* Nothing below, which means we need to relink map object for this space
1349 * use translated coordinates in case some oddness with map tiling is
1350 * evident
1351 */
1352 if(GET_MAP_OB(m,x,y)!=op) {
1353 dump_object(op);
1354 LOG(llevError,"remove_ob: GET_MAP_OB does not return object to be removed even though it appears to be on the bottom?\n%s\n", errmsg);
1355 dump_object(GET_MAP_OB(m,x,y));
1356 LOG(llevError,"%s\n",errmsg);
1357 }
1358 SET_MAP_OB(m,x,y,op->above); /* goes on above it. */
1359 }
1360 op->above=NULL;
1361 op->below=NULL;
1362
1363 if (op->map->in_memory == MAP_SAVING)
1364 return;
1365
1366 tag = op->count;
1367 check_walk_off = ! QUERY_FLAG (op, FLAG_NO_APPLY);
1368 for(tmp=GET_MAP_OB(m,x,y);tmp!=NULL;tmp=tmp->above) {
1369 /* No point updating the players look faces if he is the object
1370 * being removed.
1371 */
1372
1373 if(tmp->type==PLAYER && tmp!=op) {
1374 /* If a container that the player is currently using somehow gets
1375 * removed (most likely destroyed), update the player view
1376 * appropriately.
1377 */
1378 if (tmp->container==op) {
1379 CLEAR_FLAG(op, FLAG_APPLIED);
1380 tmp->container=NULL;
1381 }
1382 tmp->contr->socket.update_look=1;
1383 }
1384 /* See if player moving off should effect something */
1385 if (check_walk_off && ((op->move_type & tmp->move_off) &&
1386 (op->move_type & ~tmp->move_off & ~tmp->move_block)==0)) {
1387
1388 move_apply(tmp, op, NULL);
1389 if (was_destroyed (op, tag)) {
1390 LOG (llevError, "BUG: remove_ob(): name %s, archname %s destroyed "
1391 "leaving object\n", tmp->name, tmp->arch->name);
1392 }
1393 }
1394
1395 /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
1396
1397 if(tmp->above == tmp)
1398 tmp->above = NULL;
1399 last=tmp;
1400 }
1401 /* last == NULL of there are no objects on this space */
1402 if (last==NULL) {
1403 /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
1404 * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
1405 * those out anyways, and if there are any flags set right now, they won't
1406 * be correct anyways.
1407 */
1408 SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
1409 update_position(op->map, op->x, op->y);
1410 }
1411 else
1412 update_object(last, UP_OBJ_REMOVE);
1413
1414 if(QUERY_FLAG(op,FLAG_BLOCKSVIEW)|| (op->glow_radius != 0))
1415 update_all_los(op->map, op->x, op->y);
1416
1417 }
1418
1419 /*
1420 * merge_ob(op,top):
1421 *
1422 * This function goes through all objects below and including top, and
1423 * merges op to the first matching object.
1424 * If top is NULL, it is calculated.
1425 * Returns pointer to object if it succeded in the merge, otherwise NULL
1426 */
1427
1428 object *merge_ob(object *op, object *top) {
1429 if(!op->nrof)
1430 return 0;
1431 if(top==NULL)
1432 for(top=op;top!=NULL&&top->above!=NULL;top=top->above);
1433 for(;top!=NULL;top=top->below) {
1434 if(top==op)
1435 continue;
1436 if (CAN_MERGE(op,top))
1437 {
1438 top->nrof+=op->nrof;
1439 /* CLEAR_FLAG(top,FLAG_STARTEQUIP);*/
1440 op->weight = 0; /* Don't want any adjustements now */
1441 remove_ob(op);
1442 free_object(op);
1443 return top;
1444 }
1445 }
1446 return NULL;
1447 }
1448
1449 /*
1450 * same as insert_ob_in_map except it handle separate coordinates and do a clean
1451 * job preparing multi-part monsters
1452 */
1453 object *insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y){
1454 object* tmp;
1455 if (op->head)
1456 op=op->head;
1457 for (tmp=op;tmp;tmp=tmp->more){
1458 tmp->x=x+tmp->arch->clone.x;
1459 tmp->y=y+tmp->arch->clone.y;
1460 }
1461 return insert_ob_in_map (op, m, originator, flag);
1462 }
1463
1464 /*
1465 * insert_ob_in_map (op, map, originator, flag):
1466 * This function inserts the object in the two-way linked list
1467 * which represents what is on a map.
1468 * The second argument specifies the map, and the x and y variables
1469 * in the object about to be inserted specifies the position.
1470 *
1471 * originator: Player, monster or other object that caused 'op' to be inserted
1472 * into 'map'. May be NULL.
1473 *
1474 * flag is a bitmask about special things to do (or not do) when this
1475 * function is called. see the object.h file for the INS_ values.
1476 * Passing 0 for flag gives proper default values, so flag really only needs
1477 * to be set if special handling is needed.
1478 *
1479 * Return value:
1480 * new object if 'op' was merged with other object
1481 * NULL if 'op' was destroyed
1482 * just 'op' otherwise
1483 */
1484
1485 object *insert_ob_in_map (object *op, mapstruct *m, object *originator, int flag)
1486 {
1487 object *tmp, *top, *floor=NULL;
1488 sint16 x,y;
1489
1490 if (QUERY_FLAG (op, FLAG_FREED)) {
1491 LOG (llevError, "Trying to insert freed object!\n");
1492 return NULL;
1493 }
1494 if(m==NULL) {
1495 dump_object(op);
1496 LOG(llevError,"Trying to insert in null-map!\n%s\n",errmsg);
1497 return op;
1498 }
1499 if(out_of_map(m,op->x,op->y)) {
1500 dump_object(op);
1501 LOG(llevError,"Trying to insert object outside the map.\n%s\n", errmsg);
1502 #ifdef MANY_CORES
1503 /* Better to catch this here, as otherwise the next use of this object
1504 * is likely to cause a crash. Better to find out where it is getting
1505 * improperly inserted.
1506 */
1507 abort();
1508 #endif
1509 return op;
1510 }
1511 if(!QUERY_FLAG(op,FLAG_REMOVED)) {
1512 dump_object(op);
1513 LOG(llevError,"Trying to insert (map) inserted object.\n%s\n", errmsg);
1514 return op;
1515 }
1516 if(op->more!=NULL) {
1517 /* The part may be on a different map. */
1518
1519 object *more = op->more;
1520
1521 /* We really need the caller to normalize coordinates - if
1522 * we set the map, that doesn't work if the location is within
1523 * a map and this is straddling an edge. So only if coordinate
1524 * is clear wrong do we normalize it.
1525 */
1526 if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
1527 /* Debugging information so you can see the last coordinates this object had */
1528 more->ox = more->x;
1529 more->oy = more->y;
1530 more->map = get_map_from_coord(m, &more->x, &more->y);
1531 } else if (!more->map) {
1532 /* For backwards compatibility - when not dealing with tiled maps,
1533 * more->map should always point to the parent.
1534 */
1535 more->map = m;
1536 }
1537
1538 if (insert_ob_in_map(more, more->map, originator, flag) == NULL) {
1539 if ( ! op->head)
1540 LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n");
1541 return NULL;
1542 }
1543 }
1544 CLEAR_FLAG(op,FLAG_REMOVED);
1545
1546 /* Debugging information so you can see the last coordinates this object had */
1547 op->ox=op->x;
1548 op->oy=op->y;
1549
1550 /* Ideally, the caller figures this out. However, it complicates a lot
1551 * of areas of callers (eg, anything that uses find_free_spot would now
1552 * need extra work
1553 */
1554 op->map=get_map_from_coord(m, &op->x, &op->y);
1555 x = op->x;
1556 y = op->y;
1557
1558 /* this has to be done after we translate the coordinates.
1559 */
1560 if(op->nrof && !(flag & INS_NO_MERGE)) {
1561 for(tmp=GET_MAP_OB(op->map,x,y);tmp!=NULL;tmp=tmp->above)
1562 if (CAN_MERGE(op,tmp)) {
1563 op->nrof+=tmp->nrof;
1564 remove_ob(tmp);
1565 free_object(tmp);
1566 }
1567 }
1568
1569 CLEAR_FLAG(op,FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */
1570 CLEAR_FLAG(op, FLAG_INV_LOCKED);
1571 if (!QUERY_FLAG(op, FLAG_ALIVE))
1572 CLEAR_FLAG(op, FLAG_NO_STEAL);
1573
1574 if (flag & INS_BELOW_ORIGINATOR) {
1575 if (originator->map != op->map || originator->x != op->x ||
1576 originator->y != op->y) {
1577 LOG(llevError,"insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
1578 abort();
1579 }
1580 op->above = originator;
1581 op->below = originator->below;
1582 if (op->below) op->below->above = op;
1583 else SET_MAP_OB(op->map, op->x, op->y, op);
1584 /* since *below* originator, no need to update top */
1585 originator->below = op;
1586 } else {
1587 /* If there are other objects, then */
1588 if((! (flag & INS_MAP_LOAD)) && ((top=GET_MAP_OB(op->map,op->x,op->y))!=NULL)) {
1589 object *last=NULL;
1590 /*
1591 * If there are multiple objects on this space, we do some trickier handling.
1592 * We've already dealt with merging if appropriate.
1593 * Generally, we want to put the new object on top. But if
1594 * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
1595 * floor, we want to insert above that and no further.
1596 * Also, if there are spell objects on this space, we stop processing
1597 * once we get to them. This reduces the need to traverse over all of
1598 * them when adding another one - this saves quite a bit of cpu time
1599 * when lots of spells are cast in one area. Currently, it is presumed
1600 * that flying non pickable objects are spell objects.
1601 */
1602
1603 while (top != NULL) {
1604 if (QUERY_FLAG(top, FLAG_IS_FLOOR) ||
1605 QUERY_FLAG(top, FLAG_OVERLAY_FLOOR)) floor = top;
1606 if (QUERY_FLAG(top, FLAG_NO_PICK) &&
1607 (top->move_type & (MOVE_FLY_LOW |MOVE_FLY_HIGH))) {
1608 /* We insert above top, so we want this object below this */
1609 top=top->below;
1610 break;
1611 }
1612 last = top;
1613 top = top->above;
1614 }
1615 /* Don't want top to be NULL, so set it to the last valid object */
1616 top = last;
1617
1618 /* We let update_position deal with figuring out what the space
1619 * looks like instead of lots of conditions here.
1620 * makes things faster, and effectively the same result.
1621 */
1622
1623 /* Have object 'fall below' other objects that block view.
1624 * Unless those objects are exits, type 66
1625 * If INS_ON_TOP is used, don't do this processing
1626 * Need to find the object that in fact blocks view, otherwise
1627 * stacking is a bit odd.
1628 */
1629 if (!(flag & INS_ON_TOP) &&
1630 (get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL) & P_BLOCKSVIEW) &&
1631 (op->face && !op->face->visibility)) {
1632 for (last=top; last != floor; last=last->below)
1633 if (QUERY_FLAG(last, FLAG_BLOCKSVIEW)&&(last->type != EXIT)) break;
1634 /* Check to see i we found the object that blocks view,
1635 * and make sure we have a below pointer for it so that
1636 * we can get inserted below this one, which requires we
1637 * set top to the object below us.
1638 */
1639 if (last && last->below && last != floor) top=last->below;
1640 }
1641 } /* If objects on this space */
1642 if (flag & INS_MAP_LOAD)
1643 top = GET_MAP_TOP(op->map,op->x,op->y);
1644 if (flag & INS_ABOVE_FLOOR_ONLY) top = floor;
1645
1646 /* Top is the object that our object (op) is going to get inserted above.
1647 */
1648
1649 /* First object on this space */
1650 if (!top) {
1651 op->above = GET_MAP_OB(op->map, op->x, op->y);
1652 if (op->above) op->above->below = op;
1653 op->below = NULL;
1654 SET_MAP_OB(op->map, op->x, op->y, op);
1655 } else { /* get inserted into the stack above top */
1656 op->above = top->above;
1657 if (op->above) op->above->below = op;
1658 op->below = top;
1659 top->above = op;
1660 }
1661 if (op->above==NULL)
1662 SET_MAP_TOP(op->map,op->x, op->y, op);
1663 } /* else not INS_BELOW_ORIGINATOR */
1664
1665 if(op->type==PLAYER)
1666 op->contr->do_los=1;
1667
1668 /* If we have a floor, we know the player, if any, will be above
1669 * it, so save a few ticks and start from there.
1670 */
1671 if (!(flag & INS_MAP_LOAD))
1672 for(tmp=floor?floor:GET_MAP_OB(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above) {
1673 if (tmp->type == PLAYER)
1674 tmp->contr->socket.update_look=1;
1675 }
1676
1677 /* If this object glows, it may affect lighting conditions that are
1678 * visible to others on this map. But update_all_los is really
1679 * an inefficient way to do this, as it means los for all players
1680 * on the map will get recalculated. The players could very well
1681 * be far away from this change and not affected in any way -
1682 * this should get redone to only look for players within range,
1683 * or just updating the P_NEED_UPDATE for spaces within this area
1684 * of effect may be sufficient.
1685 */
1686 if(MAP_DARKNESS(op->map) && (op->glow_radius != 0))
1687 update_all_los(op->map, op->x, op->y);
1688
1689
1690 /* updates flags (blocked, alive, no magic, etc) for this map space */
1691 update_object(op,UP_OBJ_INSERT);
1692
1693
1694 /* Don't know if moving this to the end will break anything. However,
1695 * we want to have update_look set above before calling this.
1696 *
1697 * check_move_on() must be after this because code called from
1698 * check_move_on() depends on correct map flags (so functions like
1699 * blocked() and wall() work properly), and these flags are updated by
1700 * update_object().
1701 */
1702
1703 /* if this is not the head or flag has been passed, don't check walk on status */
1704
1705 if (!(flag & INS_NO_WALK_ON) && !op->head) {
1706 if (check_move_on(op, originator))
1707 return NULL;
1708
1709 /* If we are a multi part object, lets work our way through the check
1710 * walk on's.
1711 */
1712 for (tmp=op->more; tmp!=NULL; tmp=tmp->more)
1713 if (check_move_on (tmp, originator))
1714 return NULL;
1715 }
1716 return op;
1717 }
1718
1719 /* this function inserts an object in the map, but if it
1720 * finds an object of its own type, it'll remove that one first.
1721 * op is the object to insert it under: supplies x and the map.
1722 */
1723 void replace_insert_ob_in_map(const char *arch_string, object *op) {
1724 object *tmp;
1725 object *tmp1;
1726
1727 /* first search for itself and remove any old instances */
1728
1729 for(tmp=GET_MAP_OB(op->map,op->x,op->y); tmp!=NULL; tmp=tmp->above) {
1730 if(!strcmp(tmp->arch->name,arch_string)) /* same archetype */ {
1731 remove_ob(tmp);
1732 free_object(tmp);
1733 }
1734 }
1735
1736 tmp1=arch_to_object(find_archetype(arch_string));
1737
1738
1739 tmp1->x = op->x; tmp1->y = op->y;
1740 insert_ob_in_map(tmp1,op->map,op,0);
1741 }
1742
1743 /*
1744 * get_split_ob(ob,nr) splits up ob into two parts. The part which
1745 * is returned contains nr objects, and the remaining parts contains
1746 * the rest (or is removed and freed if that number is 0).
1747 * On failure, NULL is returned, and the reason put into the
1748 * global static errmsg array.
1749 */
1750
1751 object *get_split_ob(object *orig_ob, uint32 nr) {
1752 object *newob;
1753 int is_removed = (QUERY_FLAG (orig_ob, FLAG_REMOVED) != 0);
1754
1755 if(orig_ob->nrof<nr) {
1756 sprintf(errmsg,"There are only %d %ss.",
1757 orig_ob->nrof?orig_ob->nrof:1, orig_ob->name);
1758 return NULL;
1759 }
1760 newob = object_create_clone(orig_ob);
1761 if((orig_ob->nrof-=nr)<1) {
1762 if ( ! is_removed)
1763 remove_ob(orig_ob);
1764 free_object2(orig_ob, 1);
1765 }
1766 else if ( ! is_removed) {
1767 if(orig_ob->env!=NULL)
1768 sub_weight (orig_ob->env,orig_ob->weight*nr);
1769 if (orig_ob->env == NULL && orig_ob->map->in_memory!=MAP_IN_MEMORY) {
1770 strcpy(errmsg, "Tried to split object whose map is not in memory.");
1771 LOG(llevDebug,
1772 "Error, Tried to split object whose map is not in memory.\n");
1773 return NULL;
1774 }
1775 }
1776 newob->nrof=nr;
1777
1778 return newob;
1779 }
1780
1781 /*
1782 * decrease_ob_nr(object, number) decreases a specified number from
1783 * the amount of an object. If the amount reaches 0, the object
1784 * is subsequently removed and freed.
1785 *
1786 * Return value: 'op' if something is left, NULL if the amount reached 0
1787 */
1788
1789 object *decrease_ob_nr (object *op, uint32 i)
1790 {
1791 object *tmp;
1792 player *pl;
1793
1794 if (i == 0) /* objects with op->nrof require this check */
1795 return op;
1796
1797 if (i > op->nrof)
1798 i = op->nrof;
1799
1800 if (QUERY_FLAG (op, FLAG_REMOVED))
1801 {
1802 op->nrof -= i;
1803 }
1804 else if (op->env != NULL)
1805 {
1806 /* is this object in the players inventory, or sub container
1807 * therein?
1808 */
1809 tmp = is_player_inv (op->env);
1810 /* nope. Is this a container the player has opened?
1811 * If so, set tmp to that player.
1812 * IMO, searching through all the players will mostly
1813 * likely be quicker than following op->env to the map,
1814 * and then searching the map for a player.
1815 */
1816 if (!tmp) {
1817 for (pl=first_player; pl; pl=pl->next)
1818 if (pl->ob->container == op->env) break;
1819 if (pl) tmp=pl->ob;
1820 else tmp=NULL;
1821 }
1822
1823 if (i < op->nrof) {
1824 sub_weight (op->env, op->weight * i);
1825 op->nrof -= i;
1826 if (tmp) {
1827 esrv_send_item(tmp, op);
1828 }
1829 } else {
1830 remove_ob (op);
1831 op->nrof = 0;
1832 if (tmp) {
1833 esrv_del_item(tmp->contr, op->count);
1834 }
1835 }
1836 }
1837 else
1838 {
1839 object *above = op->above;
1840
1841 if (i < op->nrof) {
1842 op->nrof -= i;
1843 } else {
1844 remove_ob (op);
1845 op->nrof = 0;
1846 }
1847 /* Since we just removed op, op->above is null */
1848 for (tmp = above; tmp != NULL; tmp = tmp->above)
1849 if (tmp->type == PLAYER) {
1850 if (op->nrof)
1851 esrv_send_item(tmp, op);
1852 else
1853 esrv_del_item(tmp->contr, op->count);
1854 }
1855 }
1856
1857 if (op->nrof) {
1858 return op;
1859 } else {
1860 free_object (op);
1861 return NULL;
1862 }
1863 }
1864
1865 /*
1866 * add_weight(object, weight) adds the specified weight to an object,
1867 * and also updates how much the environment(s) is/are carrying.
1868 */
1869
1870 void add_weight (object *op, signed long weight) {
1871 while (op!=NULL) {
1872 if (op->type == CONTAINER) {
1873 weight=(signed long)(weight*(100-op->stats.Str)/100);
1874 }
1875 op->carrying+=weight;
1876 op=op->env;
1877 }
1878 }
1879
1880 /*
1881 * insert_ob_in_ob(op,environment):
1882 * This function inserts the object op in the linked list
1883 * inside the object environment.
1884 *
1885 * Eneq(@csd.uu.se): Altered insert_ob_in_ob to make things picked up enter
1886 * the inventory at the last position or next to other objects of the same
1887 * type.
1888 * Frank: Now sorted by type, archetype and magic!
1889 *
1890 * The function returns now pointer to inserted item, and return value can
1891 * be != op, if items are merged. -Tero
1892 */
1893
1894 object *insert_ob_in_ob(object *op,object *where) {
1895 object *tmp, *otmp;
1896
1897 if(!QUERY_FLAG(op,FLAG_REMOVED)) {
1898 dump_object(op);
1899 LOG(llevError,"Trying to insert (ob) inserted object.\n%s\n", errmsg);
1900 return op;
1901 }
1902 if(where==NULL) {
1903 dump_object(op);
1904 LOG(llevError,"Trying to put object in NULL.\n%s\n", errmsg);
1905 return op;
1906 }
1907 if (where->head) {
1908 LOG(llevDebug,
1909 "Warning: Tried to insert object wrong part of multipart object.\n");
1910 where = where->head;
1911 }
1912 if (op->more) {
1913 LOG(llevError, "Tried to insert multipart object %s (%d)\n",
1914 op->name, op->count);
1915 return op;
1916 }
1917 CLEAR_FLAG(op, FLAG_OBJ_ORIGINAL);
1918 CLEAR_FLAG(op, FLAG_REMOVED);
1919 if(op->nrof) {
1920 for(tmp=where->inv;tmp!=NULL;tmp=tmp->below)
1921 if ( CAN_MERGE(tmp,op) ) {
1922 /* return the original object and remove inserted object
1923 (client needs the original object) */
1924 tmp->nrof += op->nrof;
1925 /* Weight handling gets pretty funky. Since we are adding to
1926 * tmp->nrof, we need to increase the weight.
1927 */
1928 add_weight (where, op->weight*op->nrof);
1929 SET_FLAG(op, FLAG_REMOVED);
1930 free_object(op); /* free the inserted object */
1931 op = tmp;
1932 remove_ob (op); /* and fix old object's links */
1933 CLEAR_FLAG(op, FLAG_REMOVED);
1934 break;
1935 }
1936
1937 /* I assume combined objects have no inventory
1938 * We add the weight - this object could have just been removed
1939 * (if it was possible to merge). calling remove_ob will subtract
1940 * the weight, so we need to add it in again, since we actually do
1941 * the linking below
1942 */
1943 add_weight (where, op->weight*op->nrof);
1944 } else
1945 add_weight (where, (op->weight+op->carrying));
1946
1947 otmp=is_player_inv(where);
1948 if (otmp&&otmp->contr!=NULL) {
1949 if (!QUERY_FLAG(otmp,FLAG_NO_FIX_PLAYER))
1950 fix_player(otmp);
1951 }
1952
1953 op->map=NULL;
1954 op->env=where;
1955 op->above=NULL;
1956 op->below=NULL;
1957 op->x=0,op->y=0;
1958 op->ox=0,op->oy=0;
1959
1960 /* reset the light list and los of the players on the map */
1961 if((op->glow_radius!=0)&&where->map)
1962 {
1963 #ifdef DEBUG_LIGHTS
1964 LOG(llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n",
1965 op->name);
1966 #endif /* DEBUG_LIGHTS */
1967 if (MAP_DARKNESS(where->map)) update_all_los(where->map, where->x, where->y);
1968 }
1969
1970 /* Client has no idea of ordering so lets not bother ordering it here.
1971 * It sure simplifies this function...
1972 */
1973 if (where->inv==NULL)
1974 where->inv=op;
1975 else {
1976 op->below = where->inv;
1977 op->below->above = op;
1978 where->inv = op;
1979 }
1980 return op;
1981 }
1982
1983 /*
1984 * Checks if any objects has a move_type that matches objects
1985 * that effect this object on this space. Call apply() to process
1986 * these events.
1987 *
1988 * Any speed-modification due to SLOW_MOVE() of other present objects
1989 * will affect the speed_left of the object.
1990 *
1991 * originator: Player, monster or other object that caused 'op' to be inserted
1992 * into 'map'. May be NULL.
1993 *
1994 * Return value: 1 if 'op' was destroyed, 0 otherwise.
1995 *
1996 * 4-21-95 added code to check if appropriate skill was readied - this will
1997 * permit faster movement by the player through this terrain. -b.t.
1998 *
1999 * MSW 2001-07-08: Check all objects on space, not just those below
2000 * object being inserted. insert_ob_in_map may not put new objects
2001 * on top.
2002 */
2003
2004 int check_move_on (object *op, object *originator)
2005 {
2006 object *tmp;
2007 tag_t tag;
2008 mapstruct *m=op->map;
2009 int x=op->x, y=op->y;
2010 MoveType move_on, move_slow, move_block;
2011
2012 if(QUERY_FLAG(op,FLAG_NO_APPLY))
2013 return 0;
2014
2015 tag = op->count;
2016
2017 move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
2018 move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
2019 move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
2020
2021 /* if nothing on this space will slow op down or be applied,
2022 * no need to do checking below. have to make sure move_type
2023 * is set, as lots of objects don't have it set - we treat that
2024 * as walking.
2025 */
2026 if (op->move_type && !(op->move_type & move_on) && !(op->move_type & move_slow))
2027 return 0;
2028
2029 /* This is basically inverse logic of that below - basically,
2030 * if the object can avoid the move on or slow move, they do so,
2031 * but can't do it if the alternate movement they are using is
2032 * blocked. Logic on this seems confusing, but does seem correct.
2033 */
2034 if ((op->move_type & ~move_on & ~move_block) != 0 &&
2035 (op->move_type & ~move_slow & ~move_block) != 0) return 0;
2036
2037 /* The objects have to be checked from top to bottom.
2038 * Hence, we first go to the top:
2039 */
2040
2041 for (tmp=GET_MAP_OB(op->map, op->x, op->y); tmp!=NULL &&
2042 tmp->above!=NULL; tmp=tmp->above) {
2043 /* Trim the search when we find the first other spell effect
2044 * this helps performance so that if a space has 50 spell objects,
2045 * we don't need to check all of them.
2046 */
2047 if ((tmp->move_type & MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK)) break;
2048 }
2049 for(;tmp!=NULL; tmp=tmp->below) {
2050 if (tmp == op) continue; /* Can't apply yourself */
2051
2052 /* Check to see if one of the movement types should be slowed down.
2053 * Second check makes sure that the movement types not being slowed
2054 * (~slow_move) is not blocked on this space - just because the
2055 * space doesn't slow down swimming (for example), if you can't actually
2056 * swim on that space, can't use it to avoid the penalty.
2057 */
2058 if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
2059 if ((!op->move_type && tmp->move_slow & MOVE_WALK) ||
2060 ((op->move_type & tmp->move_slow) &&
2061 (op->move_type & ~tmp->move_slow & ~tmp->move_block) == 0)) {
2062
2063 float diff;
2064
2065 diff = tmp->move_slow_penalty*FABS(op->speed);
2066 if (op->type == PLAYER) {
2067 if ((QUERY_FLAG(tmp, FLAG_IS_HILLY) && find_skill_by_number(op, SK_CLIMBING)) ||
2068 (QUERY_FLAG(tmp, FLAG_IS_WOODED) && find_skill_by_number(op, SK_WOODSMAN))) {
2069 diff /= 4.0;
2070 }
2071 }
2072 op->speed_left -= diff;
2073 }
2074 }
2075
2076 /* Basically same logic as above, except now for actual apply. */
2077 if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
2078 ((op->move_type & tmp->move_on) &&
2079 (op->move_type & ~tmp->move_on & ~tmp->move_block)==0)) {
2080
2081 move_apply(tmp, op, originator);
2082 if (was_destroyed (op, tag))
2083 return 1;
2084
2085 /* what the person/creature stepped onto has moved the object
2086 * someplace new. Don't process any further - if we did,
2087 * have a feeling strange problems would result.
2088 */
2089 if (op->map != m || op->x != x || op->y != y) return 0;
2090 }
2091 }
2092 return 0;
2093 }
2094
2095 /*
2096 * present_arch(arch, map, x, y) searches for any objects with
2097 * a matching archetype at the given map and coordinates.
2098 * The first matching object is returned, or NULL if none.
2099 */
2100
2101 object *present_arch(const archetype *at, mapstruct *m, int x, int y) {
2102 object *tmp;
2103 if(m==NULL || out_of_map(m,x,y)) {
2104 LOG(llevError,"Present_arch called outside map.\n");
2105 return NULL;
2106 }
2107 for(tmp=GET_MAP_OB(m,x,y); tmp != NULL; tmp = tmp->above)
2108 if(tmp->arch == at)
2109 return tmp;
2110 return NULL;
2111 }
2112
2113 /*
2114 * present(type, map, x, y) searches for any objects with
2115 * a matching type variable at the given map and coordinates.
2116 * The first matching object is returned, or NULL if none.
2117 */
2118
2119 object *present(unsigned char type,mapstruct *m, int x,int y) {
2120 object *tmp;
2121 if(out_of_map(m,x,y)) {
2122 LOG(llevError,"Present called outside map.\n");
2123 return NULL;
2124 }
2125 for(tmp=GET_MAP_OB(m,x,y);tmp!=NULL;tmp=tmp->above)
2126 if(tmp->type==type)
2127 return tmp;
2128 return NULL;
2129 }
2130
2131 /*
2132 * present_in_ob(type, object) searches for any objects with
2133 * a matching type variable in the inventory of the given object.
2134 * The first matching object is returned, or NULL if none.
2135 */
2136
2137 object *present_in_ob(unsigned char type, const object *op) {
2138 object *tmp;
2139 for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
2140 if(tmp->type==type)
2141 return tmp;
2142 return NULL;
2143 }
2144
2145 /*
2146 * present_in_ob (type, str, object) searches for any objects with
2147 * a matching type & name variable in the inventory of the given object.
2148 * The first matching object is returned, or NULL if none.
2149 * This is mostly used by spell effect code, so that we only
2150 * have one spell effect at a time.
2151 * type can be used to narrow the search - if type is set,
2152 * the type must also match. -1 can be passed for the type,
2153 * in which case the type does not need to pass.
2154 * str is the string to match against. Note that we match against
2155 * the object name, not the archetype name. this is so that the
2156 * spell code can use one object type (force), but change it's name
2157 * to be unique.
2158 */
2159
2160 object *present_in_ob_by_name(int type, const char *str, const object *op) {
2161 object *tmp;
2162
2163 for(tmp=op->inv; tmp!=NULL; tmp=tmp->below) {
2164 if ((type==-1 || tmp->type==type) && (!strcmp(str, tmp->name)))
2165 return tmp;
2166 }
2167 return NULL;
2168 }
2169
2170 /*
2171 * present_arch_in_ob(archetype, object) searches for any objects with
2172 * a matching archetype in the inventory of the given object.
2173 * The first matching object is returned, or NULL if none.
2174 */
2175
2176 object *present_arch_in_ob(const archetype *at, const object *op) {
2177 object *tmp;
2178 for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
2179 if( tmp->arch == at)
2180 return tmp;
2181 return NULL;
2182 }
2183
2184 /*
2185 * activate recursively a flag on an object inventory
2186 */
2187 void flag_inv(object*op, int flag){
2188 object *tmp;
2189 if(op->inv)
2190 for(tmp = op->inv; tmp != NULL; tmp = tmp->below){
2191 SET_FLAG(tmp, flag);
2192 flag_inv(tmp,flag);
2193 }
2194 }/*
2195 * desactivate recursively a flag on an object inventory
2196 */
2197 void unflag_inv(object*op, int flag){
2198 object *tmp;
2199 if(op->inv)
2200 for(tmp = op->inv; tmp != NULL; tmp = tmp->below){
2201 CLEAR_FLAG(tmp, flag);
2202 unflag_inv(tmp,flag);
2203 }
2204 }
2205
2206 /*
2207 * set_cheat(object) sets the cheat flag (WAS_WIZ) in the object and in
2208 * all it's inventory (recursively).
2209 * If checksums are used, a player will get set_cheat called for
2210 * him/her-self and all object carried by a call to this function.
2211 */
2212
2213 void set_cheat(object *op) {
2214 SET_FLAG(op, FLAG_WAS_WIZ);
2215 flag_inv(op, FLAG_WAS_WIZ);
2216 }
2217
2218 /*
2219 * find_free_spot(object, map, x, y, start, stop) will search for
2220 * a spot at the given map and coordinates which will be able to contain
2221 * the given object. start and stop specifies how many squares
2222 * to search (see the freearr_x/y[] definition).
2223 * It returns a random choice among the alternatives found.
2224 * start and stop are where to start relative to the free_arr array (1,9
2225 * does all 4 immediate directions). This returns the index into the
2226 * array of the free spot, -1 if no spot available (dir 0 = x,y)
2227 * Note - this only checks to see if there is space for the head of the
2228 * object - if it is a multispace object, this should be called for all
2229 * pieces.
2230 * Note2: This function does correctly handle tiled maps, but does not
2231 * inform the caller. However, insert_ob_in_map will update as
2232 * necessary, so the caller shouldn't need to do any special work.
2233 * Note - updated to take an object instead of archetype - this is necessary
2234 * because arch_blocked (now ob_blocked) needs to know the movement type
2235 * to know if the space in question will block the object. We can't use
2236 * the archetype because that isn't correct if the monster has been
2237 * customized, changed states, etc.
2238 */
2239
2240 int find_free_spot(const object *ob, mapstruct *m,int x,int y,int start,int stop) {
2241 int i,index=0, flag;
2242 static int altern[SIZEOFFREE];
2243
2244 for(i=start;i<stop;i++) {
2245 flag = ob_blocked(ob,m,x+freearr_x[i],y+freearr_y[i]);
2246 if(!flag)
2247 altern[index++]=i;
2248
2249 /* Basically, if we find a wall on a space, we cut down the search size.
2250 * In this way, we won't return spaces that are on another side of a wall.
2251 * This mostly work, but it cuts down the search size in all directions -
2252 * if the space being examined only has a wall to the north and empty
2253 * spaces in all the other directions, this will reduce the search space
2254 * to only the spaces immediately surrounding the target area, and
2255 * won't look 2 spaces south of the target space.
2256 */
2257 else if ((flag & AB_NO_PASS) && maxfree[i]<stop)
2258 stop=maxfree[i];
2259 }
2260 if(!index) return -1;
2261 return altern[RANDOM()%index];
2262 }
2263
2264 /*
2265 * find_first_free_spot(archetype, mapstruct, x, y) works like
2266 * find_free_spot(), but it will search max number of squares.
2267 * But it will return the first available spot, not a random choice.
2268 * Changed 0.93.2: Have it return -1 if there is no free spot available.
2269 */
2270
2271 int find_first_free_spot(const object *ob, mapstruct *m,int x,int y) {
2272 int i;
2273 for(i=0;i<SIZEOFFREE;i++) {
2274 if(!ob_blocked(ob,m,x+freearr_x[i],y+freearr_y[i]))
2275 return i;
2276 }
2277 return -1;
2278 }
2279
2280 /*
2281 * The function permute(arr, begin, end) randomly reorders the array
2282 * arr[begin..end-1].
2283 */
2284 static void permute(int *arr, int begin, int end)
2285 {
2286 int i, j, tmp, len;
2287
2288 len = end-begin;
2289 for(i = begin; i < end; i++)
2290 {
2291 j = begin+RANDOM()%len;
2292
2293 tmp = arr[i];
2294 arr[i] = arr[j];
2295 arr[j] = tmp;
2296 }
2297 }
2298
2299 /* new function to make monster searching more efficient, and effective!
2300 * This basically returns a randomized array (in the passed pointer) of
2301 * the spaces to find monsters. In this way, it won't always look for
2302 * monsters to the north first. However, the size of the array passed
2303 * covers all the spaces, so within that size, all the spaces within
2304 * the 3x3 area will be searched, just not in a predictable order.
2305 */
2306 void get_search_arr(int *search_arr)
2307 {
2308 int i;
2309
2310 for(i = 0; i < SIZEOFFREE; i++)
2311 {
2312 search_arr[i] = i;
2313 }
2314
2315 permute(search_arr, 1, SIZEOFFREE1+1);
2316 permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
2317 permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
2318 }
2319
2320 /*
2321 * find_dir(map, x, y, exclude) will search some close squares in the
2322 * given map at the given coordinates for live objects.
2323 * It will not considered the object given as exclude among possible
2324 * live objects.
2325 * It returns the direction toward the first/closest live object if finds
2326 * any, otherwise 0.
2327 * Perhaps incorrectly, but I'm making the assumption that exclude
2328 * is actually want is going to try and move there. We need this info
2329 * because we have to know what movement the thing looking to move
2330 * there is capable of.
2331 */
2332
2333 int find_dir(mapstruct *m, int x, int y, object *exclude) {
2334 int i,max=SIZEOFFREE, mflags;
2335 sint16 nx, ny;
2336 object *tmp;
2337 mapstruct *mp;
2338 MoveType blocked, move_type;
2339
2340 if (exclude && exclude->head) {
2341 exclude = exclude->head;
2342 move_type = exclude->move_type;
2343 } else {
2344 /* If we don't have anything, presume it can use all movement types. */
2345 move_type=MOVE_ALL;
2346 }
2347
2348 for(i=1;i<max;i++) {
2349 mp = m;
2350 nx = x + freearr_x[i];
2351 ny = y + freearr_y[i];
2352
2353 mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
2354 if (mflags & P_OUT_OF_MAP) {
2355 max = maxfree[i];
2356 } else {
2357 blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny);
2358
2359 if ((move_type & blocked) == move_type) {
2360 max=maxfree[i];
2361 } else if (mflags & P_IS_ALIVE) {
2362 for (tmp=GET_MAP_OB(mp,nx,ny); tmp!= NULL; tmp=tmp->above) {
2363 if ((QUERY_FLAG(tmp,FLAG_MONSTER) || tmp->type==PLAYER) &&
2364 (tmp != exclude ||(tmp->head && tmp->head != exclude))) {
2365 break;
2366 }
2367 }
2368 if(tmp) {
2369 return freedir[i];
2370 }
2371 }
2372 }
2373 }
2374 return 0;
2375 }
2376
2377 /*
2378 * distance(object 1, object 2) will return the square of the
2379 * distance between the two given objects.
2380 */
2381
2382 int distance(const object *ob1, const object *ob2) {
2383 int i;
2384 i= (ob1->x - ob2->x)*(ob1->x - ob2->x)+
2385 (ob1->y - ob2->y)*(ob1->y - ob2->y);
2386 return i;
2387 }
2388
2389 /*
2390 * find_dir_2(delta-x,delta-y) will return a direction in which
2391 * an object which has subtracted the x and y coordinates of another
2392 * object, needs to travel toward it.
2393 */
2394
2395 int find_dir_2(int x, int y) {
2396 int q;
2397 if(!y)
2398 q= -300*x;
2399 else
2400 q=x*100/y;
2401 if(y>0) {
2402 if(q < -242)
2403 return 3 ;
2404 if (q < -41)
2405 return 2 ;
2406 if (q < 41)
2407 return 1 ;
2408 if (q < 242)
2409 return 8 ;
2410 return 7 ;
2411 }
2412 if (q < -242)
2413 return 7 ;
2414 if (q < -41)
2415 return 6 ;
2416 if (q < 41)
2417 return 5 ;
2418 if (q < 242)
2419 return 4 ;
2420 return 3 ;
2421 }
2422
2423 /*
2424 * absdir(int): Returns a number between 1 and 8, which represent
2425 * the "absolute" direction of a number (it actually takes care of
2426 * "overflow" in previous calculations of a direction).
2427 */
2428
2429 int absdir(int d) {
2430 while(d<1) d+=8;
2431 while(d>8) d-=8;
2432 return d;
2433 }
2434
2435 /*
2436 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is
2437 * between two directions (which are expected to be absolute (see absdir())
2438 */
2439
2440 int dirdiff(int dir1, int dir2) {
2441 int d;
2442 d = abs(dir1 - dir2);
2443 if(d>4)
2444 d = 8 - d;
2445 return d;
2446 }
2447
2448 /* peterm:
2449 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster.
2450 * Basically, this is a table of directions, and what directions
2451 * one could go to go back to us. Eg, entry 15 below is 4, 14, 16.
2452 * This basically means that if direction is 15, then it could either go
2453 * direction 4, 14, or 16 to get back to where we are.
2454 * Moved from spell_util.c to object.c with the other related direction
2455 * functions.
2456 */
2457
2458 int reduction_dir[SIZEOFFREE][3] = {
2459 {0,0,0}, /* 0 */
2460 {0,0,0}, /* 1 */
2461 {0,0,0}, /* 2 */
2462 {0,0,0}, /* 3 */
2463 {0,0,0}, /* 4 */
2464 {0,0,0}, /* 5 */
2465 {0,0,0}, /* 6 */
2466 {0,0,0}, /* 7 */
2467 {0,0,0}, /* 8 */
2468 {8,1,2}, /* 9 */
2469 {1,2,-1}, /* 10 */
2470 {2,10,12}, /* 11 */
2471 {2,3,-1}, /* 12 */
2472 {2,3,4}, /* 13 */
2473 {3,4,-1}, /* 14 */
2474 {4,14,16}, /* 15 */
2475 {5,4,-1}, /* 16 */
2476 {4,5,6}, /* 17 */
2477 {6,5,-1}, /* 18 */
2478 {6,20,18}, /* 19 */
2479 {7,6,-1}, /* 20 */
2480 {6,7,8}, /* 21 */
2481 {7,8,-1}, /* 22 */
2482 {8,22,24}, /* 23 */
2483 {8,1,-1}, /* 24 */
2484 {24,9,10}, /* 25 */
2485 {9,10,-1}, /* 26 */
2486 {10,11,-1}, /* 27 */
2487 {27,11,29}, /* 28 */
2488 {11,12,-1}, /* 29 */
2489 {12,13,-1}, /* 30 */
2490 {12,13,14}, /* 31 */
2491 {13,14,-1}, /* 32 */
2492 {14,15,-1}, /* 33 */
2493 {33,15,35}, /* 34 */
2494 {16,15,-1}, /* 35 */
2495 {17,16,-1}, /* 36 */
2496 {18,17,16}, /* 37 */
2497 {18,17,-1}, /* 38 */
2498 {18,19,-1}, /* 39 */
2499 {41,19,39}, /* 40 */
2500 {19,20,-1}, /* 41 */
2501 {20,21,-1}, /* 42 */
2502 {20,21,22}, /* 43 */
2503 {21,22,-1}, /* 44 */
2504 {23,22,-1}, /* 45 */
2505 {45,47,23}, /* 46 */
2506 {23,24,-1}, /* 47 */
2507 {24,9,-1}}; /* 48 */
2508
2509 /* Recursive routine to step back and see if we can
2510 * find a path to that monster that we found. If not,
2511 * we don't bother going toward it. Returns 1 if we
2512 * can see a direct way to get it
2513 * Modified to be map tile aware -.MSW
2514 */
2515
2516
2517 int can_see_monsterP(mapstruct *m, int x, int y,int dir) {
2518 sint16 dx, dy;
2519 int mflags;
2520
2521 if(dir<0) return 0; /* exit condition: invalid direction */
2522
2523 dx = x + freearr_x[dir];
2524 dy = y + freearr_y[dir];
2525
2526 mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
2527
2528 /* This functional arguably was incorrect before - it was
2529 * checking for P_WALL - that was basically seeing if
2530 * we could move to the monster - this is being more
2531 * literal on if we can see it. To know if we can actually
2532 * move to the monster, we'd need the monster passed in or
2533 * at least its move type.
2534 */
2535 if (mflags & (P_OUT_OF_MAP | P_BLOCKSVIEW)) return 0;
2536
2537 /* yes, can see. */
2538 if(dir < 9) return 1;
2539 return can_see_monsterP(m, x, y, reduction_dir[dir][0]) |
2540 can_see_monsterP(m,x,y, reduction_dir[dir][1]) |
2541 can_see_monsterP(m,x,y, reduction_dir[dir][2]);
2542 }
2543
2544
2545
2546 /*
2547 * can_pick(picker, item): finds out if an object is possible to be
2548 * picked up by the picker. Returnes 1 if it can be
2549 * picked up, otherwise 0.
2550 *
2551 * Cf 0.91.3 - don't let WIZ's pick up anything - will likely cause
2552 * core dumps if they do.
2553 *
2554 * Add a check so we can't pick up invisible objects (0.93.8)
2555 */
2556
2557 int can_pick(const object *who, const object *item) {
2558 return /*QUERY_FLAG(who,FLAG_WIZ)||*/
2559 (item->weight>0&&!QUERY_FLAG(item,FLAG_NO_PICK)&&
2560 !QUERY_FLAG(item,FLAG_ALIVE)&&!item->invisible &&
2561 (who->type==PLAYER||item->weight<who->weight/3));
2562 }
2563
2564
2565 /*
2566 * create clone from object to another
2567 */
2568 object *object_create_clone (object *asrc) {
2569 object *dst = NULL,*tmp,*src,*part,*prev, *item;
2570
2571 if(!asrc) return NULL;
2572 src = asrc;
2573 if(src->head)
2574 src = src->head;
2575
2576 prev = NULL;
2577 for(part = src; part; part = part->more) {
2578 tmp = get_object();
2579 copy_object(part,tmp);
2580 tmp->x -= src->x;
2581 tmp->y -= src->y;
2582 if(!part->head) {
2583 dst = tmp;
2584 tmp->head = NULL;
2585 } else {
2586 tmp->head = dst;
2587 }
2588 tmp->more = NULL;
2589 if(prev)
2590 prev->more = tmp;
2591 prev = tmp;
2592 }
2593 /*** copy inventory ***/
2594 for(item = src->inv; item; item = item->below) {
2595 (void) insert_ob_in_ob(object_create_clone(item),dst);
2596 }
2597
2598 return dst;
2599 }
2600
2601 /* return true if the object was destroyed, 0 otherwise */
2602 int was_destroyed (const object *op, tag_t old_tag)
2603 {
2604 /* checking for FLAG_FREED isn't necessary, but makes this function more
2605 * robust */
2606 return op->count != old_tag || QUERY_FLAG (op, FLAG_FREED);
2607 }
2608
2609 /* GROS - Creates an object using a string representing its content. */
2610 /* Basically, we save the content of the string to a temp file, then call */
2611 /* load_object on it. I admit it is a highly inefficient way to make things, */
2612 /* but it was simple to make and allows reusing the load_object function. */
2613 /* Remember not to use load_object_str in a time-critical situation. */
2614 /* Also remember that multiparts objects are not supported for now. */
2615
2616 object* load_object_str(const char *obstr)
2617 {
2618 object *op;
2619 FILE *tempfile;
2620 char filename[MAX_BUF];
2621 sprintf(filename,"%s/cfloadobstr2044",settings.tmpdir);
2622 tempfile=fopen(filename,"w");
2623 if (tempfile == NULL)
2624 {
2625 LOG(llevError,"Error - Unable to access load object temp file\n");
2626 return NULL;
2627 };
2628 fprintf(tempfile,obstr);
2629 fclose(tempfile);
2630
2631 op=get_object();
2632
2633 tempfile=fopen(filename,"r");
2634 if (tempfile == NULL)
2635 {
2636 LOG(llevError,"Error - Unable to read object temp file\n");
2637 return NULL;
2638 };
2639 load_object(tempfile,op,LO_NEWFILE,0);
2640 LOG(llevDebug," load str completed, object=%s\n",op->name);
2641 CLEAR_FLAG(op,FLAG_REMOVED);
2642 fclose(tempfile);
2643 return op;
2644 }
2645
2646 /* This returns the first object in who's inventory that
2647 * has the same type and subtype match.
2648 * returns NULL if no match.
2649 */
2650 object *find_obj_by_type_subtype(const object *who, int type, int subtype)
2651 {
2652 object *tmp;
2653
2654 for (tmp=who->inv; tmp; tmp=tmp->below)
2655 if (tmp->type == type && tmp->subtype == subtype) return tmp;
2656
2657 return NULL;
2658 }
2659
2660 /* If ob has a field named key, return the link from the list,
2661 * otherwise return NULL.
2662 *
2663 * key must be a passed in shared string - otherwise, this won't
2664 * do the desired thing.
2665 */
2666 key_value * get_ob_key_link(const object * ob, const char * key) {
2667 key_value * link;
2668
2669 for (link = ob->key_values; link != NULL; link = link->next) {
2670 if (link->key == key) {
2671 return link;
2672 }
2673 }
2674
2675 return NULL;
2676 }
2677
2678 /*
2679 * Returns the value of op has an extra_field for key, or NULL.
2680 *
2681 * The argument doesn't need to be a shared string.
2682 *
2683 * The returned string is shared.
2684 */
2685 const char * get_ob_key_value(const object * op, const char * const key) {
2686 key_value * link;
2687 const char * canonical_key;
2688
2689 canonical_key = find_string(key);
2690
2691 if (canonical_key == NULL) {
2692 /* 1. There being a field named key on any object
2693 * implies there'd be a shared string to find.
2694 * 2. Since there isn't, no object has this field.
2695 * 3. Therefore, *this* object doesn't have this field.
2696 */
2697 return NULL;
2698 }
2699
2700 /* This is copied from get_ob_key_link() above -
2701 * only 4 lines, and saves the function call overhead.
2702 */
2703 for (link = op->key_values; link != NULL; link = link->next) {
2704 if (link->key == canonical_key) {
2705 return link->value;
2706 }
2707 }
2708 return NULL;
2709 }
2710
2711
2712 /*
2713 * Updates the canonical_key in op to value.
2714 *
2715 * canonical_key is a shared string (value doesn't have to be).
2716 *
2717 * Unless add_key is TRUE, it won't add fields, only change the value of existing
2718 * keys.
2719 *
2720 * Returns TRUE on success.
2721 */
2722 int set_ob_key_value_s(object * op, const char * canonical_key, const char * value, int add_key) {
2723 key_value * field = NULL, *last=NULL;
2724
2725 for (field=op->key_values; field != NULL; field=field->next) {
2726 if (field->key != canonical_key) {
2727 last = field;
2728 continue;
2729 }
2730
2731 if (field->value) FREE_AND_CLEAR_STR(field->value);
2732 if (value)
2733 field->value = add_string(value);
2734 else {
2735 /* Basically, if the archetype has this key set,
2736 * we need to store the null value so when we save
2737 * it, we save the empty value so that when we load,
2738 * we get this value back again.
2739 */
2740 if (get_ob_key_link(&op->arch->clone, canonical_key))
2741 field->value = NULL;
2742 else {
2743 /* Delete this link */
2744 if (field->key) FREE_AND_CLEAR_STR(field->key);
2745 if (field->value) FREE_AND_CLEAR_STR(field->value);
2746 if (last) last->next = field->next;
2747 else op->key_values = field->next;
2748 free(field);
2749 }
2750 }
2751 return TRUE;
2752 }
2753 /* IF we get here, key doesn't exist */
2754
2755 /* No field, we'll have to add it. */
2756
2757 if (!add_key) {
2758 return FALSE;
2759 }
2760 /* There isn't any good reason to store a null
2761 * value in the key/value list. If the archetype has
2762 * this key, then we should also have it, so shouldn't
2763 * be here. If user wants to store empty strings,
2764 * should pass in ""
2765 */
2766 if (value == NULL) return TRUE;
2767
2768 field = malloc(sizeof(key_value));
2769
2770 field->key = add_refcount(canonical_key);
2771 field->value = add_string(value);
2772 /* Usual prepend-addition. */
2773 field->next = op->key_values;
2774 op->key_values = field;
2775
2776 return TRUE;
2777 }
2778
2779 /*
2780 * Updates the key in op to value.
2781 *
2782 * If add_key is FALSE, this will only update existing keys,
2783 * and not add new ones.
2784 * In general, should be little reason FALSE is ever passed in for add_key
2785 *
2786 * Returns TRUE on success.
2787 */
2788 int set_ob_key_value(object * op, const char * key, const char * value, int add_key) {
2789 const char * canonical_key = NULL;
2790 int floating_ref = FALSE;
2791 int ret;
2792
2793 /* HACK This mess is to make sure set_ob_value() passes a shared string
2794 * to get_ob_key_link(), without leaving a leaked refcount.
2795 */
2796
2797 canonical_key = find_string(key);
2798 if (canonical_key == NULL) {
2799 canonical_key = add_string(key);
2800 floating_ref = TRUE;
2801 }
2802
2803 ret = set_ob_key_value_s(op, canonical_key, value, add_key);
2804
2805 if (floating_ref) {
2806 free_string(canonical_key);
2807 }
2808
2809 return ret;
2810 }