Crossfire Server, Branch 1.12  R12190
object.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_object_c =
00003  *   "$Id: object.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2001 Mark Wedel & Crossfire Development Team
00010     Copyright (C) 1992 Frank Tore Johansen
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026     The authors can be reached via e-mail at crossfire-devel@real-time.com
00027 */
00028 
00034 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
00035    sub/add_weight will transcend the environment updating the carrying
00036    variable. */
00037 
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <global.h>
00041 #ifndef WIN32 /* ---win32 exclude headers */
00042 #include <stdio.h>
00043 #include <sys/types.h>
00044 #include <sys/uio.h>
00045 #endif /* win32 */
00046 #include <object.h>
00047 #include <skills.h>
00048 #include <loader.h>
00049 #include <sproto.h>
00050 #include "stringbuffer.h"
00051 
00052 static int compare_ob_value_lists_one(const object *, const object *);
00053 static int compare_ob_value_lists(const object *, const object *);
00054 static void expand_objects(void);
00055 static void permute(int *, int, int);
00056 static int set_ob_key_value_s(object *, const char *, const char *, int);
00057 static void increase_ob_nr(object *op, uint32 i);
00058 
00059 #ifdef MEMORY_DEBUG
00060 int nroffreeobjects = 0;  
00061 int nrofallocobjects = 0; 
00062 #undef OBJ_EXPAND
00063 #define OBJ_EXPAND 1
00064 #else
00065 object objarray[STARTMAX]; 
00066 int nroffreeobjects = STARTMAX;  
00067 int nrofallocobjects = STARTMAX; 
00068 #endif
00069 
00070 object *objects;           
00071 object *free_objects;      
00072 object *active_objects;    
00075 short freearr_x[SIZEOFFREE] = {
00076     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,
00077     0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
00078 };
00079 
00081 short freearr_y[SIZEOFFREE] = {
00082     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,
00083     -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
00084 };
00085 
00087 int maxfree[SIZEOFFREE] = {
00088     0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
00089     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
00090 };
00091 
00093 int freedir[SIZEOFFREE] = {
00094     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,
00095     1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
00096 };
00097 
00108 static int compare_ob_value_lists_one(const object *wants, const object *has) {
00109     key_value *wants_field;
00110 
00111     /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both
00112      * objects with lists are rare, and lists stay short. If not, use a
00113      * different structure or at least keep the lists sorted...
00114      */
00115 
00116     /* For each field in wants, */
00117     for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
00118         key_value *has_field;
00119 
00120         /* Look for a field in has with the same key. */
00121         has_field = get_ob_key_link(has, wants_field->key);
00122 
00123         if (has_field == NULL) {
00124             /* No field with that name. */
00125             return FALSE;
00126         }
00127 
00128         /* Found the matching field. */
00129         if (has_field->value != wants_field->value) {
00130             /* Values don't match, so this half of the comparison is false. */
00131             return FALSE;
00132         }
00133 
00134         /* If we get here, we found a match. Now for the next field in wants. */
00135     }
00136 
00137     /* If we get here, every field in wants has a matching field in has. */
00138     return TRUE;
00139 }
00140 
00149 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
00150     /* However, there may be fields in has which aren't partnered in wants,
00151      * so we need to run the comparison *twice*. :(
00152      */
00153     return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
00154 }
00155 
00178 int can_merge(object *ob1, object *ob2) {
00179 
00180     /* A couple quicksanity checks */
00181     if ((ob1 == ob2) || (ob1->type != ob2->type))
00182         return 0;
00183 
00184     if (ob1->speed != ob2->speed)
00185         return 0;
00186     /* Note sure why the following is the case - either the object has to
00187      * be animated or have a very low speed.  Is this an attempted monster
00188      * check?
00189      */
00190     /*TODO is this check really needed?*/
00191     if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
00192         return 0;
00193 
00194     /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
00195      * value could not be stored in a sint32 (which unfortunately sometimes is
00196      * used to store nrof).
00197      */
00198     if (ob1->nrof+ob2->nrof >= 1UL<<31)
00199         return 0;
00200 
00201     /* This is really a spellbook check - really, we should
00202      * check all objects in the inventory.
00203     */
00204     /*TODO is this check really needed?*/
00205     if (ob1->inv || ob2->inv) {
00206         /* if one object has inventory but the other doesn't, not equiv */
00207         if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
00208             return 0;
00209 
00210         /* Now check to see if the two inventory objects could merge */
00211         if (!can_merge(ob1->inv, ob2->inv))
00212             return 0;
00213 
00214         /* inventory ok - still need to check rest of this object to see
00215          * if it is valid.
00216          */
00217     }
00218 
00219     /* If the objects have been identified, set the BEEN_APPLIED flag.
00220      * This is to the comparison of the flags below will be OK.  We
00221      * just can't ignore the been applied or identified flags, as they
00222      * are not equal - just if it has been identified, the been_applied
00223      * flags lose any meaning.
00224      */
00225 
00226     /*TODO is this hack on BEEN_APPLIED really needed? */
00227     if (QUERY_FLAG(ob1, FLAG_IDENTIFIED))
00228         SET_FLAG(ob1, FLAG_BEEN_APPLIED);
00229 
00230     if (QUERY_FLAG(ob2, FLAG_IDENTIFIED))
00231         SET_FLAG(ob2, FLAG_BEEN_APPLIED);
00232 
00233 
00234     /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
00235     if ((ob1->arch != ob2->arch)
00236     || (ob1->flags[0] != ob2->flags[0])
00237     || (ob1->flags[1] != ob2->flags[1])
00238     || (ob1->flags[2] != ob2->flags[2])
00239     || ((ob1->flags[3]&~0x4) != (ob2->flags[3]&~0x4)) /* ignore CLIENT_SENT */
00240     || (ob1->name != ob2->name)
00241     || (ob1->title != ob2->title)
00242     || (ob1->msg != ob2->msg)
00243     || (ob1->weight != ob2->weight)
00244     || (ob1->item_power != ob2->item_power)
00245     || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
00246     || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
00247     || (ob1->attacktype != ob2->attacktype)
00248     || (ob1->magic != ob2->magic)
00249     || (ob1->slaying != ob2->slaying)
00250     || (ob1->skill != ob2->skill)
00251     || (ob1->value != ob2->value)
00252     || (ob1->animation_id != ob2->animation_id)
00253     || (ob1->client_type != ob2->client_type)
00254     || (ob1->materialname != ob2->materialname)
00255     || (ob1->lore != ob2->lore)
00256     || (ob1->subtype != ob2->subtype)
00257     || (ob1->move_type != ob2->move_type)
00258     || (ob1->move_block != ob2->move_block)
00259     || (ob1->move_allow != ob2->move_allow)
00260     || (ob1->move_on != ob2->move_on)
00261     || (ob1->move_off != ob2->move_off)
00262     || (ob1->move_slow != ob2->move_slow)
00263     || (ob1->move_slow_penalty != ob2->move_slow_penalty)
00264     || (ob1->map_layer != ob2->map_layer))
00265         return 0;
00266 
00267     /* Don't merge objects that are applied.  With the new 'body' code,
00268      * it is possible for most any character to have more than one of
00269      * some items equipped, and we don't want those to merge.
00270      */
00271     if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
00272         return 0;
00273 
00274     if (ob1->key_values != NULL || ob2->key_values != NULL) {
00275         /* At least one of these has key_values. */
00276         if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
00277             /* One has fields, but the other one doesn't. */
00278             return 0;
00279         } else {
00280             return compare_ob_value_lists(ob1, ob2);
00281         }
00282     }
00283 
00284     /*TODO should this really be limited to scrolls?*/
00285     switch (ob1->type) {
00286     case SCROLL:
00287         if (ob1->level != ob2->level)
00288             return 0;
00289         break;
00290 
00291     }
00292 
00293     /* Don't merge items with differing custom names. */
00294     if (ob1->custom_name != ob2->custom_name)
00295         return 0;
00296 
00297     /* Everything passes, must be OK. */
00298     return 1;
00299 }
00300 
00316 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
00317 signed long sum_weight(object *op) {
00318     signed long sum;
00319     object *inv;
00320 
00321     for (sum = 0, inv = op->inv; inv != NULL; inv = inv->below) {
00322         if (inv->inv)
00323             sum_weight(inv);
00324         sum += inv->carrying+inv->weight*(inv->nrof ? inv->nrof : 1);
00325     }
00326     if (op->type == CONTAINER && op->stats.Str)
00327         sum = (sum*(100-op->stats.Str))/100;
00328     op->carrying = sum;
00329     return sum;
00330 }
00331 
00339 object *object_get_env_recursive(object *op) {
00340     while (op->env != NULL)
00341         op = op->env;
00342     return op;
00343 }
00344 
00356 object *get_player_container(object *op) {
00357     for (; op != NULL && op->type != PLAYER; op = op->env)
00358         /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
00359         if (op->env == op)
00360             op->env = NULL;
00361     return op;
00362 }
00363 
00372 void dump_object(object *op, StringBuffer *sb) {
00373     if (op == NULL) {
00374         stringbuffer_append_string(sb, "[NULL pointer]");
00375         return;
00376     }
00377 
00378     /*  object *tmp;*/
00379 
00380     if (op->arch != NULL) {
00381         stringbuffer_append_string(sb, "arch ");
00382         stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
00383         stringbuffer_append_string(sb, "\n");
00384 
00385         get_ob_diff(sb, op, &empty_archetype->clone);
00386         if (op->more) {
00387             stringbuffer_append_printf(sb, "more %u\n", op->more->count);
00388         }
00389         if (op->head) {
00390             stringbuffer_append_printf(sb, "head %u\n", op->head->count);
00391         }
00392         if (op->env) {
00393             stringbuffer_append_printf(sb, "env %u\n", op->env->count);
00394         }
00395         if (op->inv) {
00396             stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
00397         }
00398         if (op->owner) {
00399             stringbuffer_append_printf(sb, "owner %u\n", op->owner->count);
00400         }
00401         stringbuffer_append_string(sb, "end\n");
00402     } else {
00403         stringbuffer_append_string(sb, "Object ");
00404         stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
00405         stringbuffer_append_string(sb, "\nend\n");
00406     }
00407 }
00408 
00416 void dump_all_objects(void) {
00417     object *op;
00418 
00419     for (op = objects; op != NULL; op = op->next) {
00420         StringBuffer *sb;
00421         char *diff;
00422 
00423         sb = stringbuffer_new();
00424         dump_object(op, sb);
00425         diff = stringbuffer_finish(sb);
00426         LOG(llevDebug, "Object %d\n:%s\n", op->count, diff);
00427         free(diff);
00428     }
00429 }
00430 
00439 object *find_object(tag_t i) {
00440     object *op;
00441 
00442     for (op = objects; op != NULL; op = op->next)
00443         if (op->count == i)
00444             break;
00445     return op;
00446 }
00447 
00459 object *find_object_name(const char *str) {
00460     const char *name = add_string(str);
00461     object *op;
00462 
00463     for (op = objects; op != NULL; op = op->next)
00464         if (op->name == name)
00465             break;
00466     free_string(name);
00467     return op;
00468 }
00469 
00479 void free_all_object_data(void) {
00480 #ifdef MEMORY_DEBUG
00481     object *op, *next;
00482 
00483     for (op = free_objects; op != NULL; ) {
00484         next = op->next;
00485         free(op);
00486         nrofallocobjects--;
00487         nroffreeobjects--;
00488         op = next;
00489     }
00490 
00491     for (op = objects; op != NULL; ) {
00492         next = op->next;
00493         if (!QUERY_FLAG(op, FLAG_FREED)) {
00494             LOG(llevDebug, "non freed object: %s\n", op->name);
00495         }
00496         op = next;
00497     }
00498 #endif
00499 
00500     LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
00501 }
00502 
00524 object *get_owner(object *op) {
00525     if (op->owner == NULL)
00526         return NULL;
00527 
00528     if (!QUERY_FLAG(op->owner, FLAG_FREED)
00529     && !QUERY_FLAG(op->owner, FLAG_REMOVED)
00530     && op->owner->count == op->ownercount)
00531         return op->owner;
00532     LOG(llevError, "I had to clean an owner when in get_owner, this isn't my job.\n");
00533     op->owner = NULL;
00534     op->ownercount = 0;
00535     return NULL;
00536 }
00537 
00544 void clear_owner(object *op) {
00545     if (!op)
00546         return;
00547 
00548     op->owner = NULL;
00549     op->ownercount = 0;
00550 }
00551 
00564 void set_owner(object *op, object *owner) {
00565     if (op == NULL)
00566         return;
00567     if (owner == NULL) {
00568         clear_owner(op);
00569         return;
00570     }
00571 
00572     /* next line added to allow objects which own objects */
00573     /* Add a check for ownercounts in here, as I got into an endless loop
00574      * with the fireball owning a poison cloud which then owned the
00575      * fireball.  I believe that was caused by one of the objects getting
00576      * freed and then another object replacing it.  Since the ownercounts
00577      * didn't match, this check is valid and I believe that cause is valid.
00578      */
00579     while (owner->owner
00580     && owner != owner->owner
00581     && owner->ownercount == owner->owner->count)
00582         owner = owner->owner;
00583 
00584     /* IF the owner still has an owner, we did not resolve to a final owner.
00585      * so lets not add to that.
00586      */
00587     if (owner->owner) {
00588         LOG(llevError, "owner id %d could not be resolved to a parent owner in set_owner(). This is bad!"
00589             "owner=%p owner->owner=%p owner->ownercount=%d owner->owner->count=%d\n",
00590             owner->count, owner, owner->owner, owner->ownercount, owner->owner->count);
00591         return;
00592     }
00593 
00594     op->owner = owner;
00595     op->ownercount = owner->count;
00596 }
00597 
00614 void copy_owner(object *op, object *clone) {
00615     object *owner = get_owner(clone);
00616     if (owner == NULL) {
00617         /* players don't have owners - they own themselves.  Update
00618          * as appropriate.
00619          */
00620         /*TODO owner=self is dangerous and should be avoided*/
00621         if (clone->type == PLAYER)
00622             owner = clone;
00623         else
00624             return;
00625     }
00626     set_owner(op, owner);
00627 
00628 }
00629 
00639 void reset_object(object *op) {
00640     op->name = NULL;
00641     op->name_pl = NULL;
00642     op->title = NULL;
00643     op->race = NULL;
00644     op->slaying = NULL;
00645     op->skill = NULL;
00646     op->msg = NULL;
00647     op->materialname = NULL;
00648     op->lore = NULL;
00649     clear_object(op);
00650 }
00651 
00659 void free_key_values(object *op) {
00660     key_value *i;
00661     key_value *next = NULL;
00662 
00663     if (op->key_values == NULL)
00664         return;
00665 
00666     for (i = op->key_values; i != NULL; i = next) {
00667         /* Store next *first*. */
00668         next = i->next;
00669 
00670         if (i->key)
00671             FREE_AND_CLEAR_STR(i->key);
00672         if (i->value)
00673             FREE_AND_CLEAR_STR(i->value);
00674         i->next = NULL;
00675         free(i);
00676     }
00677 
00678     op->key_values = NULL;
00679 }
00680 
00688 void clear_object(object *op) {
00689 
00690     /*TODO this comment must be investigated*/
00691     /* redo this to be simpler/more efficient. Was also seeing
00692      * crashes in the old code.  Move this to the top - am
00693      * seeing periodic crashes in this code, and would like to have
00694      * as much info available as possible (eg, object name).
00695      */
00696     free_key_values(op);
00697     free_dialog_information(op);
00698 
00699     /* the memset will clear all these values for us, but we need
00700      * to reduce the refcount on them.
00701      */
00702     if (op->name != NULL) FREE_AND_CLEAR_STR(op->name);
00703     if (op->name_pl != NULL) FREE_AND_CLEAR_STR(op->name_pl);
00704     if (op->title != NULL) FREE_AND_CLEAR_STR(op->title);
00705     if (op->race != NULL) FREE_AND_CLEAR_STR(op->race);
00706     if (op->slaying != NULL) FREE_AND_CLEAR_STR(op->slaying);
00707     if (op->skill != NULL) FREE_AND_CLEAR_STR(op->skill);
00708     if (op->msg != NULL) FREE_AND_CLEAR_STR(op->msg);
00709     if (op->lore != NULL) FREE_AND_CLEAR_STR(op->lore);
00710     if (op->materialname != NULL) FREE_AND_CLEAR_STR(op->materialname);
00711     if (op->discrete_damage != NULL) FREE_AND_CLEAR(op->discrete_damage);
00712 
00713     /* Remove object from friendly list if needed. */
00714     if (QUERY_FLAG(op, FLAG_FRIENDLY))
00715         remove_friendly_object(op);
00716 
00717     memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
00718     /* Below here, we clear things that are not done by the memset,
00719      * or set default values that are not zero.
00720      */
00721     /* This is more or less true */
00722     SET_FLAG(op, FLAG_REMOVED);
00723 
00724 
00725     op->contr = NULL;
00726     op->below = NULL;
00727     op->above = NULL;
00728     op->inv = NULL;
00729     op->container = NULL;
00730     op->env = NULL;
00731     op->more = NULL;
00732     op->head = NULL;
00733     op->map = NULL;
00734     op->active_next = NULL;
00735     op->active_prev = NULL;
00736     /* What is not cleared is next, prev, and count */
00737 
00738     op->expmul = 1.0;
00739     op->face = blank_face;
00740     op->attacked_by_count = -1;
00741     if (settings.casting_time)
00742         op->casting_time = -1;
00743 }
00744 
00758 void copy_object(object *op2, object *op) {
00759     int is_freed = QUERY_FLAG(op, FLAG_FREED), is_removed = QUERY_FLAG(op, FLAG_REMOVED);
00760 
00761     /* Decrement the refcounts, but don't bother zeroing the fields;
00762     they'll be overwritten by memcpy. */
00763     if (op->name != NULL) free_string(op->name);
00764     if (op->name_pl != NULL) free_string(op->name_pl);
00765     if (op->anim_suffix != NULL) free_string(op->anim_suffix);
00766     if (op->title != NULL) free_string(op->title);
00767     if (op->race != NULL) free_string(op->race);
00768     if (op->slaying != NULL) free_string(op->slaying);
00769     if (op->skill != NULL) free_string(op->skill);
00770     if (op->msg != NULL) free_string(op->msg);
00771     if (op->lore != NULL) free_string(op->lore);
00772     if (op->materialname != NULL) free_string(op->materialname);
00773     if (op->custom_name != NULL) free_string(op->custom_name);
00774     if (op->discrete_damage != NULL) FREE_AND_CLEAR(op->discrete_damage);
00775     if (op->spell_tags != NULL) FREE_AND_CLEAR(op->spell_tags);
00776 
00777     /* Basically, same code as from clear_object() */
00778 
00779     free_key_values(op);
00780     free_dialog_information(op);
00781 
00782     /* op is the destination, op2 is the source. */
00783     (void)memcpy((void *)((char *)op+offsetof(object, name)),
00784                 (void *)((char *)op2+offsetof(object, name)),
00785                 sizeof(object)-offsetof(object, name));
00786 
00787     if (is_freed) SET_FLAG(op, FLAG_FREED);
00788     if (is_removed) SET_FLAG(op, FLAG_REMOVED);
00789     if (op->name != NULL) add_refcount(op->name);
00790     if (op->name_pl != NULL) add_refcount(op->name_pl);
00791     if (op->anim_suffix != NULL) add_refcount(op->anim_suffix);
00792     if (op->title != NULL) add_refcount(op->title);
00793     if (op->race != NULL) add_refcount(op->race);
00794     if (op->slaying != NULL) add_refcount(op->slaying);
00795     if (op->skill != NULL) add_refcount(op->skill);
00796     if (op->lore != NULL) add_refcount(op->lore);
00797     if (op->msg != NULL) add_refcount(op->msg);
00798     if (op->custom_name != NULL) add_refcount(op->custom_name);
00799     if (op->materialname != NULL) add_refcount(op->materialname);
00800     if (op->discrete_damage != NULL) {
00801         op->discrete_damage = malloc(sizeof(sint16)*NROFATTACKS);
00802         memcpy(op->discrete_damage, op2->discrete_damage, sizeof(sint16)*NROFATTACKS);
00803     }
00804 
00805     if (op->spell_tags != NULL) {
00806         op->spell_tags = malloc(sizeof(tag_t)*SPELL_TAG_SIZE);
00807         memcpy(op->spell_tags, op2->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
00808     }
00809 
00810     /* If archetype is a temporary one, we need to update reference count, because
00811      * that archetype will be freed by free_object when the last object is removed.
00812      */
00813     if (op->arch->reference_count > 0)
00814         op->arch->reference_count++;
00815 
00816     if (op2->speed < 0)
00817         op->speed_left = op2->speed_left-RANDOM()%200/100.0;
00818 
00819     /* Copy over key_values, if any. */
00820     if (op2->key_values != NULL) {
00821         key_value *tail = NULL;
00822         key_value *i;
00823 
00824         op->key_values = NULL;
00825 
00826         for (i = op2->key_values; i != NULL; i = i->next) {
00827             key_value *new_link = malloc(sizeof(key_value));
00828 
00829             new_link->next = NULL;
00830             new_link->key = add_refcount(i->key);
00831             if (i->value)
00832                 new_link->value = add_refcount(i->value);
00833             else
00834                 new_link->value = NULL;
00835 
00836             /* Try and be clever here, too. */
00837             if (op->key_values == NULL) {
00838                 op->key_values = new_link;
00839                 tail = new_link;
00840             } else {
00841                 tail->next = new_link;
00842                 tail = new_link;
00843             }
00844         }
00845     }
00846 
00847     /* This way, dialog information will be parsed again when/if needed. */
00848     CLEAR_FLAG(op, FLAG_DIALOG_PARSED);
00849 
00850     update_ob_speed(op);
00851 }
00852 
00862 void copy_object_with_inv(object *src_ob, object *dest_ob) {
00863     object *walk, *tmp;
00864     copy_object(src_ob, dest_ob);
00865 
00866     for (walk = src_ob->inv; walk != NULL; walk = walk->below) {
00867         tmp = get_object();
00868         copy_object(walk, tmp);
00869         insert_ob_in_ob(tmp, dest_ob);
00870     }
00871 }
00872 
00880 static void expand_objects(void) {
00881     int i;
00882     object *new;
00883 
00884     new = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
00885 
00886     if (new == NULL)
00887         fatal(OUT_OF_MEMORY);
00888     free_objects = new;
00889     new[0].prev = NULL;
00890     new[0].next = &new[1],
00891     SET_FLAG(&(new[0]), FLAG_REMOVED);
00892     SET_FLAG(&(new[0]), FLAG_FREED);
00893 
00894     for (i = 1; i < OBJ_EXPAND-1; i++) {
00895         new[i].next = &new[i+1],
00896         new[i].prev = &new[i-1],
00897         SET_FLAG(&(new[i]), FLAG_REMOVED);
00898         SET_FLAG(&(new[i]), FLAG_FREED);
00899     }
00900     new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2],
00901     new[OBJ_EXPAND-1].next = NULL,
00902     SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_REMOVED);
00903     SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_FREED);
00904 
00905     nrofallocobjects += OBJ_EXPAND;
00906     nroffreeobjects += OBJ_EXPAND;
00907 }
00908 
00921 object *get_object(void) {
00922     object *op;
00923 
00924     if (free_objects == NULL) {
00925         expand_objects();
00926     }
00927     op = free_objects;
00928 #ifdef MEMORY_DEBUG
00929     /* The idea is hopefully by doing a realloc, the memory
00930      * debugging program will now use the current stack trace to
00931      * report leaks.
00932      */
00933     /* FIXME: However this doesn't work since free_object2() sometimes add
00934      * objects back to the free_objects linked list, and some functions mess
00935      * with the object after return of free_object2(). This is bad and should be
00936      * fixed. But it would need fairly extensive changes and a lot of debugging.
00937      * So until that is fixed, skip realloc() here unless MEMORY_DEBUG is set to
00938      * a value greater than 1. We do this in order at least make MEMORY_DEBUG
00939      * slightly useful.
00940      */
00941 #if MEMORY_DEBUG > 1
00942     op = realloc(op, sizeof(object));
00943 #endif
00944     SET_FLAG(op, FLAG_REMOVED);
00945     SET_FLAG(op, FLAG_FREED);
00946 #endif
00947 
00948     if (!QUERY_FLAG(op, FLAG_FREED)) {
00949         LOG(llevError, "Fatal: Getting busy object.\n");
00950 #ifdef MANY_CORES
00951         abort();
00952 #endif
00953     }
00954     free_objects = op->next;
00955     if (free_objects != NULL)
00956         free_objects->prev = NULL;
00957     op->count = ++ob_count;
00958     op->name = NULL;
00959     op->name_pl = NULL;
00960     op->title = NULL;
00961     op->race = NULL;
00962     op->slaying = NULL;
00963     op->skill = NULL;
00964     op->lore = NULL;
00965     op->msg = NULL;
00966     op->materialname = NULL;
00967     op->next = objects;
00968     op->prev = NULL;
00969     op->active_next = NULL;
00970     op->active_prev = NULL;
00971     op->discrete_damage = NULL;
00972     op->spell_tags = NULL;
00973     if (objects != NULL)
00974         objects->prev = op;
00975     objects = op;
00976     clear_object(op);
00977     SET_FLAG(op, FLAG_REMOVED);
00978     nroffreeobjects--;
00979     return op;
00980 }
00981 
00990 void update_turn_face(object *op) {
00991     if (!QUERY_FLAG(op, FLAG_IS_TURNABLE) || op->arch == NULL)
00992         return;
00993     SET_ANIMATION(op, op->direction);
00994     update_object(op, UP_OBJ_FACE);
00995 }
00996 
01008 void update_ob_speed(object *op) {
01009     /* FIXME what the hell is this crappy hack?*/
01010     extern int arch_init;
01011 
01012     /* No reason putting the archetypes objects on the speed list,
01013      * since they never really need to be updated.
01014      */
01015 
01016     if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
01017         LOG(llevError, "Object %s is freed but has speed.\n", op->name);
01018 #ifdef MANY_CORES
01019         abort();
01020 #else
01021         op->speed = 0;
01022 #endif
01023     }
01024     if (arch_init) {
01025         return;
01026     }
01027     if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
01028         /* If already on active list, don't do anything */
01029         /* TODO this check can probably be simplified a lot */
01030         if (op->active_next || op->active_prev || op == active_objects)
01031             return;
01032 
01033         /* process_events() expects us to insert the object at the beginning
01034          * of the list. */
01035         op->active_next = active_objects;
01036         if (op->active_next != NULL)
01037             op->active_next->active_prev = op;
01038         active_objects = op;
01039     } else {
01040         /* If not on the active list, nothing needs to be done */
01041         if (!op->active_next && !op->active_prev && op != active_objects)
01042             return;
01043 
01044         if (op->active_prev == NULL) {
01045             active_objects = op->active_next;
01046             if (op->active_next != NULL)
01047                 op->active_next->active_prev = NULL;
01048         } else {
01049             op->active_prev->active_next = op->active_next;
01050             if (op->active_next)
01051                 op->active_next->active_prev = op->active_prev;
01052         }
01053         op->active_next = NULL;
01054         op->active_prev = NULL;
01055     }
01056 }
01057 
01070 void remove_from_active_list(object *op) {
01071     /* If not on the active list, nothing needs to be done */
01072     if (!op->active_next && !op->active_prev && op != active_objects)
01073         return;
01074 
01075     if (op->active_prev == NULL) {
01076         active_objects = op->active_next;
01077         if (op->active_next != NULL)
01078             op->active_next->active_prev = NULL;
01079     } else {
01080         op->active_prev->active_next = op->active_next;
01081         if (op->active_next)
01082             op->active_next->active_prev = op->active_prev;
01083     }
01084     op->active_next = NULL;
01085     op->active_prev = NULL;
01086 }
01087 
01112 void update_object(object *op, int action) {
01113     int update_now = 0, flags;
01114     MoveType move_on, move_off, move_block, move_slow;
01115     object *pl;
01116 
01117     if (op == NULL) {
01118         /* this should never happen */
01119         LOG(llevDebug, "update_object() called for NULL object.\n");
01120         return;
01121     }
01122 
01123     if (op->env != NULL) {
01124         /* Animation is currently handled by client, so nothing
01125         * to do in this case.
01126         */
01127         return;
01128     }
01129 
01130     /* If the map is saving, don't do anything as everything is
01131      * going to get freed anyways.
01132      */
01133     if (!op->map || op->map->in_memory == MAP_SAVING)
01134         return;
01135 
01136     /* make sure the object is within map boundaries */
01137     if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
01138     || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
01139         LOG(llevError, "update_object() called for object out of map!\n");
01140 #ifdef MANY_CORES
01141         abort();
01142 #endif
01143         return;
01144     }
01145 
01146     flags = GET_MAP_FLAGS(op->map, op->x, op->y);
01147     SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
01148     move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
01149     move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
01150     move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
01151     move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
01152 
01153     if (action == UP_OBJ_INSERT) {
01154         if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) && !(flags&P_BLOCKSVIEW))
01155             update_now = 1;
01156 
01157         if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
01158             update_now = 1;
01159 
01160         if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
01161             update_now = 1;
01162 
01163         if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
01164             update_now = 1;
01165 
01166         if ((move_on|op->move_on) != move_on)
01167             update_now = 1;
01168         if ((move_off|op->move_off) != move_off)
01169             update_now = 1;
01170         /* This isn't perfect, but I don't expect a lot of objects to
01171          * to have move_allow right now.
01172          */
01173         if (((move_block|op->move_block)&~op->move_allow) != move_block)
01174             update_now = 1;
01175         if ((move_slow|op->move_slow) != move_slow)
01176             update_now = 1;
01177 
01178         if (op->type == PLAYER)
01179             update_now = 1;
01180     /* if the object is being removed, we can't make intelligent
01181      * decisions, because remove_ob can't really pass the object
01182      * that is being removed.
01183      */
01184     } else if (action == UP_OBJ_REMOVE) {
01185         update_now = 1;
01186     } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
01187         /* In addition to sending info to client, need to update space
01188          * information.
01189          */
01190         if (action == UP_OBJ_CHANGE)
01191             update_now = 1;
01192 
01193         /* There is a player on this space - we may need to send an
01194          * update to the client.
01195          * If this object is supposed to be animated by the client,
01196          * nothing to do here - let the client animate it.
01197          * We can't use FLAG_ANIMATE, as that is basically set for
01198          * all objects with multiple faces, regardless if they are animated.
01199          * (levers have it set for example).
01200          */
01201         if (flags&P_PLAYER
01202         && !QUERY_FLAG(op, FLAG_CLIENT_ANIM_SYNC)
01203         && !QUERY_FLAG(op, FLAG_CLIENT_ANIM_RANDOM)) {
01204             pl = GET_MAP_PLAYER(op->map, op->x, op->y);
01205 
01206             /* If update_look is set, we're going to send this entire space
01207              * to the client, so no reason to send face information now.
01208              */
01209             if (!pl->contr->socket.update_look) {
01210                 esrv_update_item(UPD_FACE, pl, op);
01211             }
01212         }
01213     } else {
01214         LOG(llevError, "update_object called with invalid action: %d\n", action);
01215     }
01216 
01217     if (update_now) {
01218         SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
01219         update_position(op->map, op->x, op->y);
01220     }
01221 
01222     if (op->more != NULL)
01223         update_object(op->more, action);
01224 }
01225 
01238 void free_object(object *ob) {
01239     free_object2(ob, 0);
01240 }
01241 
01258 void free_object2(object *ob, int free_inventory) {
01259     object *tmp, *op;
01260 
01261     if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
01262         StringBuffer *sb;
01263         char *diff;
01264 
01265         LOG(llevDebug, "Free object called with non removed object\n");
01266         sb = stringbuffer_new();
01267         dump_object(ob, sb);
01268         diff = stringbuffer_finish(sb);
01269         LOG(llevError, diff);
01270         free(diff);
01271 #ifdef MANY_CORES
01272         abort();
01273 #endif
01274     }
01275     if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
01276         LOG(llevMonster, "Warning: tried to free friendly object.\n");
01277         remove_friendly_object(ob);
01278     }
01279     if (QUERY_FLAG(ob, FLAG_FREED)) {
01280         StringBuffer *sb;
01281         char *diff;
01282 
01283         sb = stringbuffer_new();
01284         dump_object(ob, sb);
01285         diff = stringbuffer_finish(sb);
01286         LOG(llevError, "Trying to free freed object.\n%s\n", diff);
01287         free(diff);
01288         return;
01289     }
01290 
01291     /* Handle for plugin destroy event */
01292     execute_event(ob, EVENT_DESTROY, NULL, NULL, NULL, SCRIPT_FIX_NOTHING);
01293 
01294     if (ob->inv) {
01295         /* Only if the space blocks everything do we not process -
01296          * if some form of movemnt is allowed, let objects
01297          * drop on that space.
01298          */
01299         if (free_inventory
01300         || ob->map == NULL
01301         || ob->map->in_memory != MAP_IN_MEMORY
01302         || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
01303             op = ob->inv;
01304             while (op != NULL) {
01305                 tmp = op->below;
01306                 remove_ob(op);
01307                 free_object2(op, free_inventory);
01308                 op = tmp;
01309             }
01310         } else { /* Put objects in inventory onto this space */
01311             op = ob->inv;
01312             while (op != NULL) {
01313                 tmp = op->below;
01314                 remove_ob(op);
01315                 if (QUERY_FLAG(op, FLAG_STARTEQUIP)||QUERY_FLAG(op, FLAG_NO_DROP)
01316                 || op->type == RUNE
01317                 || op->type == TRAP
01318                 || QUERY_FLAG(op, FLAG_IS_A_TEMPLATE))
01319                     free_object(op);
01320                 else {
01321                     object *part;
01322 
01323                     /* If it's a multi-tile object, scatter dropped items randomly */
01324                     if (ob->more) {
01325                         int partcount = 0;
01326                         /* Get the number of non-head parts */
01327                         for (part = ob; part; part = part->more) {
01328                             partcount++;
01329                         }
01330                         /* Select a random part */
01331                         partcount = RANDOM()%partcount;
01332                         for (part = ob; partcount > 0; partcount--) {
01333                             part = part->more;
01334                         }
01335                     } else {
01336                         part = ob;
01337                     }
01338 
01339                     if (QUERY_FLAG(op, FLAG_ALIVE)) {
01340                         int pos;
01341 
01342                         pos = find_free_spot(op, part->map, part->x, part->y, 0, SIZEOFFREE);
01343                         if (pos == -1)
01344                             free_object(op);
01345                         else {
01346                             op->x = part->x+freearr_x[pos];
01347                             op->y = part->y+freearr_y[pos];
01348                             insert_ob_in_map(op, part->map, NULL, 0); /* Insert in same map as the envir */
01349                         }
01350                     } else {
01351                         op->x = part->x;
01352                         op->y = part->y;
01353                         insert_ob_in_map(op, part->map, NULL, 0); /* Insert in same map as the envir */
01354                     }
01355                 }
01356                 op = tmp;
01357             }
01358         }
01359     }
01360 
01361     if (ob->more != NULL) {
01362         free_object2(ob->more, free_inventory);
01363         ob->more = NULL;
01364     }
01365 
01366     /* Remove object from the active list */
01367     ob->speed = 0;
01368     update_ob_speed(ob);
01369 
01370     SET_FLAG(ob, FLAG_FREED);
01371     ob->count = 0;
01372 
01373     /* Remove this object from the list of used objects */
01374     if (ob->prev == NULL) {
01375         objects = ob->next;
01376         if (objects != NULL)
01377             objects->prev = NULL;
01378     } else {
01379         ob->prev->next = ob->next;
01380         if (ob->next != NULL)
01381             ob->next->prev = ob->prev;
01382     }
01383 
01384     if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
01385     if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
01386     if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
01387     if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
01388     if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
01389     if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
01390     if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
01391     if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
01392     if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
01393     if (ob->discrete_damage != NULL) FREE_AND_CLEAR(ob->discrete_damage);
01394     if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
01395 
01396     /* Why aren't events freed? */
01397     free_key_values(ob);
01398 
01399     free_dialog_information(ob);
01400 
01401     /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
01402     if (ob->arch && ob->arch->reference_count > 0) {
01403         if (--ob->arch->reference_count == 0) {
01404             free_arch(ob->arch);
01405         }
01406     }
01407 
01408 #if defined(MEMORY_DEBUG) && (MEMORY_DEBUG > 2)
01409     /* memset() to clear it then set flags and finally free it. This will
01410      * help detect bad use after return.
01411      */
01412     memset(ob, 0, sizeof(object));
01413     SET_FLAG(ob, FLAG_REMOVED);
01414     SET_FLAG(ob, FLAG_FREED);
01415     free(ob);
01416 #else
01417     /* Now link it with the free_objects list: */
01418     ob->prev = NULL;
01419     ob->next = free_objects;
01420     if (free_objects != NULL)
01421         free_objects->prev = ob;
01422     free_objects = ob;
01423     nroffreeobjects++;
01424 #endif
01425 }
01426 
01433 int count_free(void) {
01434     int i = 0;
01435     object *tmp = free_objects;
01436 
01437     while (tmp != NULL)
01438         tmp = tmp->next,
01439         i++;
01440     return i;
01441 }
01442 
01449 int count_used(void) {
01450     int i = 0;
01451     object *tmp = objects;
01452 
01453     while (tmp != NULL)
01454         tmp = tmp->next,
01455         i++;
01456     return i;
01457 }
01458 
01465 int count_active(void) {
01466     int i = 0;
01467     object *tmp = active_objects;
01468 
01469     while (tmp != NULL)
01470         tmp = tmp->active_next,
01471         i++;
01472     return i;
01473 }
01474 
01489 void sub_weight(object *op, signed long weight) {
01490     while (op != NULL) {
01491         if (op->type == CONTAINER) {
01492             weight = (signed long)(weight*(100-op->stats.Str)/100);
01493         }
01494         op->carrying -= weight;
01495         op = op->env;
01496     }
01497 }
01498 
01515 void remove_ob(object *op) {
01516     object *tmp, *last = NULL;
01517     object *otmp;
01518     tag_t tag;
01519     int check_walk_off;
01520     mapstruct *m;
01521     sint16 x, y;
01522 
01523     if (QUERY_FLAG(op, FLAG_REMOVED)) {
01524         StringBuffer *sb;
01525         char *diff;
01526 
01527         sb = stringbuffer_new();
01528         dump_object(op, sb);
01529         diff = stringbuffer_finish(sb);
01530         LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
01531         free(diff);
01532         abort();
01533     }
01534     if (op->more != NULL)
01535         remove_ob(op->more);
01536 
01537     SET_FLAG(op, FLAG_REMOVED);
01538 
01539     /*
01540      * In this case, the object to be removed is in someones
01541      * inventory.
01542      */
01543     /* TODO try to call a generic inventory weight adjusting function like sub_weight */
01544     if (op->env != NULL) {
01545         if (op->nrof)
01546             sub_weight(op->env, op->weight*op->nrof);
01547         else
01548             sub_weight(op->env, op->weight+op->carrying);
01549 
01550         /* Update in two cases: item is in a player, or in a container the player is looking into. */
01551         if (op->env->contr != NULL && op->head == NULL) {
01552             if (LOOK_OBJ(op))
01553                 esrv_del_item(op->env->contr, op->count);
01554         } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
01555             player *pl = NULL;
01556 
01557             if (op->env->env && op->env->env->contr)
01558                 /* Container is in player's inventory. */
01559                 pl = op->env->env->contr;
01560             else if (op->env->map) {
01561                 /* Container on map, look above for player. */
01562                 object *above = op->env->above;
01563 
01564                 while (above && !above->contr)
01565                     above = above->above;
01566                 if (above)
01567                     pl = above->contr;
01568             }
01569             if (pl && LOOK_OBJ(op))
01570                 esrv_del_item(pl, op->count);
01571         }
01572 
01573         /* NO_FIX_PLAYER is set when a great many changes are being
01574          * made to players inventory.  If set, avoiding the call
01575          * to save cpu time.
01576          */
01577         if ((otmp = get_player_container(op->env)) != NULL
01578         && otmp->contr
01579         && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
01580             fix_object(otmp);
01581 
01582         if (op->above != NULL)
01583             op->above->below = op->below;
01584         else
01585             op->env->inv = op->below;
01586 
01587         if (op->below != NULL)
01588             op->below->above = op->above;
01589 
01590         /* we set up values so that it could be inserted into
01591          * the map, but we don't actually do that - it is up
01592          * to the caller to decide what we want to do.
01593          */
01594         op->x = op->env->x;
01595         op->y = op->env->y;
01596         op->ox = op->x;
01597         op->oy = op->y;
01598         op->map = op->env->map;
01599         op->above = NULL;
01600         op->below = NULL;
01601         op->env = NULL;
01602         return;
01603     }
01604 
01605     /* If we get here, we are removing it from a map */
01606     if (op->map == NULL)
01607         return;
01608 
01609     if (op->contr != NULL && !op->contr->hidden)
01610         op->map->players--;
01611 
01612     x = op->x;
01613     y = op->y;
01614     m = get_map_from_coord(op->map, &x, &y);
01615 
01616     if (!m) {
01617         LOG(llevError, "remove_ob called when object was on map but appears to not be within valid coordinates? %s (%d,%d)\n", op->map->path, op->x, op->y);
01618         abort();
01619     }
01620     if (op->map != m) {
01621         LOG(llevError, "remove_ob: Object not really on map it claimed to be on? %s != %s, %d,%d != %d,%d\n", op->map->path, m->path, op->x, op->y, x, y);
01622     }
01623 
01624     /* link the object above us */
01625     if (op->above)
01626         op->above->below = op->below;
01627     else
01628         SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
01629 
01630     /* Relink the object below us, if there is one */
01631     if (op->below) {
01632         op->below->above = op->above;
01633     } else {
01634         /* Nothing below, which means we need to relink map object for this space
01635          * use translated coordinates in case some oddness with map tiling is
01636          * evident
01637          */
01638         /*TODO is this check really needed?*/
01639         if (GET_MAP_OB(m, x, y) != op) {
01640             StringBuffer *sb;
01641             char *diff;
01642 
01643             sb = stringbuffer_new();
01644             dump_object(op, sb);
01645             diff = stringbuffer_finish(sb);
01646             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", diff);
01647             free(diff);
01648 
01649             sb = stringbuffer_new();
01650             dump_object(GET_MAP_OB(m, x, y), sb);
01651             diff = stringbuffer_finish(sb);
01652             LOG(llevError, "%s\n", diff);
01653             free(diff);
01654         }
01655         SET_MAP_OB(m, x, y, op->above);  /* goes on above it. */
01656     }
01657     op->above = NULL;
01658     op->below = NULL;
01659 
01660     if (op->map->in_memory == MAP_SAVING)
01661         return;
01662 
01663     tag = op->count;
01664     check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
01665     for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
01666         /* No point updating the players look faces if he is the object
01667          * being removed.
01668          */
01669 
01670         if (tmp->type == PLAYER && tmp != op) {
01671             /* If a container that the player is currently using somehow gets
01672              * removed (most likely destroyed), update the player view
01673              * appropriately.
01674             */
01675             if (tmp->container == op) {
01676                 CLEAR_FLAG(op, FLAG_APPLIED);
01677                 tmp->container = NULL;
01678             }
01679             tmp->contr->socket.update_look = 1;
01680         }
01681         /* See if player moving off should effect something */
01682         if (check_walk_off
01683         && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
01684             ob_move_on(tmp, op, NULL);
01685             if (was_destroyed(op, tag)) {
01686                 LOG(llevError, "BUG: remove_ob(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
01687             }
01688         }
01689 
01690         /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
01691         if (tmp->above == tmp)
01692             tmp->above = NULL;
01693         last = tmp;
01694     }
01695     /* last == NULL or there are no objects on this space */
01696     if (last == NULL) {
01697         /* set P_NEED_UPDATE, otherwise update_position will complain.  In theory,
01698         * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
01699         * those out anyways, and if there are any flags set right now, they won't
01700         * be correct anyways.
01701         */
01702         SET_MAP_FLAGS(op->map, op->x, op->y,  P_NEED_UPDATE);
01703         update_position(op->map, op->x, op->y);
01704     } else
01705         update_object(last, UP_OBJ_REMOVE);
01706 
01707     if (QUERY_FLAG(op, FLAG_BLOCKSVIEW)|| (op->glow_radius != 0))
01708         update_all_los(op->map, op->x, op->y);
01709 }
01710 
01724 object *merge_ob(object *op, object *top) {
01725     if (!op->nrof)
01726         return NULL;
01727 
01728     if (top == NULL)
01729         for (top = op; top != NULL && top->above != NULL; top = top->above)
01730             ;
01731     for (; top != NULL; top = top->below) {
01732         if (top == op)
01733             continue;
01734         if (can_merge(op, top)) {
01735             increase_ob_nr(top, op->nrof);
01736             op->weight = 0; /* Don't want any adjustements now */
01737             remove_ob(op);
01738             free_object(op);
01739             return top;
01740         }
01741     }
01742     return NULL;
01743 }
01744 
01761 object *insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
01762     object *tmp;
01763 
01764     if (op->head)
01765         op = op->head;
01766     for (tmp = op; tmp; tmp = tmp->more) {
01767         tmp->x = x+tmp->arch->clone.x;
01768         tmp->y = y+tmp->arch->clone.y;
01769         if (op != tmp && !tmp->map)
01770             tmp->map = op->map ? op->map : m;
01771     }
01772     return insert_ob_in_map(op, m, originator, flag);
01773 }
01774 
01792 void merge_spell(object *op, sint16 x, sint16 y) {
01793     object *tmp, *above;
01794     int i;
01795 
01796     /* We try to do some merging of spell objects - if something has same owner,
01797      * is same type of spell, and going in the same direction, it is somewhat
01798      * mergable.
01799      *
01800      * If the spell object has an other_arch, don't merge - when the spell
01801      * does something, like explodes, it will use this other_arch, and
01802      * if we merge, there is no easy way to make the correct values be
01803      * set on this new object (values should be doubled, tripled, etc.)
01804      *
01805      * We also care about speed - only process objects that will not be
01806      * active this tick.  Without this, the results are incorrect - think
01807      * of a case where tmp would normally get processed this tick, but
01808      * get merges with op, which does not get processed.
01809      */
01810     for (tmp = GET_MAP_OB(op->map, x, y); tmp != NULL; tmp = above) {
01811         above = tmp->above;
01812 
01813         if (op->type == tmp->type
01814         && op->subtype == tmp->subtype
01815         && op->direction == tmp->direction
01816         && op->owner == tmp->owner && op->ownercount == tmp->ownercount
01817         && op->range == tmp->range
01818         && op->stats.wc == tmp->stats.wc
01819         && op->level == tmp->level
01820         && op->attacktype == tmp->attacktype
01821         && op->speed == tmp->speed
01822         && !tmp->other_arch
01823         && (tmp->speed_left+tmp->speed) < 0.0
01824         && op != tmp) {
01825             /* Quick test - if one or the other objects already have hash tables
01826              * set up, and that hash bucket contains a value that doesn't
01827              * match what we want to set it up, we won't be able to merge.
01828              * Note that these two if statements are the same, except
01829              * for which object they are checking against.  They could
01830              * be merged, but the line wrapping would be large enough
01831              * that IMO it would become difficult to read the different clauses
01832              * so its cleaner just to do 2 statements - MSW
01833              */
01834             if (op->spell_tags
01835             && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)
01836             && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
01837                 continue;
01838 
01839             if (tmp->spell_tags
01840             && !OB_SPELL_TAG_MATCH(tmp, op->stats.maxhp)
01841             && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
01842                 continue;
01843 
01844             /* If we merge, the data from tmp->spell_tags gets copied into op.
01845              * so we need to make sure that slot isn't filled up.
01846              */
01847             if (tmp->spell_tags
01848             && !OB_SPELL_TAG_MATCH(tmp, tmp->stats.maxhp)
01849             && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
01850                 continue;
01851 
01852             /* If both objects have spell_tags, we need to see if there are conflicting
01853              * values - if there are, we won't be able to merge then.
01854              */
01855             if (tmp->spell_tags && op->spell_tags) {
01856                 int need_copy = 0;
01857 
01858                 for (i = 0; i < SPELL_TAG_SIZE; i++) {
01859                     /* If the two tag values in the hash are set, but are
01860                      * not set to the same value, then these objects
01861                      * can not be merged.
01862                      */
01863                     if (op->spell_tags[i] && tmp->spell_tags[i]
01864                     && op->spell_tags[i] != tmp->spell_tags[i]) {
01865                         statistics.spell_hash_full++;
01866                         break;
01867                     }
01868                     /* If one tag is set and the other is not, that is
01869                      * fine, but we have to note that we need to copy
01870                      * the data in that case.
01871                      */
01872                     if ((!op->spell_tags[i] && tmp->spell_tags[i])
01873                     || (op->spell_tags[i] && !tmp->spell_tags[i])) {
01874                         need_copy = 1;
01875                     }
01876                 }
01877                 /* If we did not get through entire array, it means
01878                  * we got a conflicting hash, and so we won't be
01879                  * able to merge these - just continue processing
01880                  * object on this space.
01881                  */
01882                 if (i <= SPELL_TAG_SIZE)
01883                     continue;
01884 
01885                 /* Ok - everything checked out - we should be able to
01886                  * merge tmp in op.  So lets copy the tag data if
01887                  * needed.  Note that this is a selective copy, as
01888                  * we don't want to clear values that may be set in op.
01889                  */
01890                 if (need_copy) {
01891                     for (i = 0; i < SPELL_TAG_SIZE; i++)
01892                         if (!op->spell_tags[i]
01893                         && tmp->spell_tags[i]
01894                         && tmp->spell_tags[i] != op->stats.maxhp)
01895                             op->spell_tags[i] = tmp->spell_tags[i];
01896                 }
01897                 FREE_AND_CLEAR(tmp->spell_tags);
01898             }
01899 
01900             /* if tmp has a spell_tags table, copy it to op and free tmps */
01901             if (tmp->spell_tags && !op->spell_tags) {
01902                 op->spell_tags = tmp->spell_tags;
01903                 tmp->spell_tags = NULL;
01904 
01905                 /* We don't need to keep a copy of our maxhp value
01906                  * in the copied over value
01907                 */
01908                 if (OB_SPELL_TAG_MATCH(op, op->stats.maxhp))
01909                     OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
01910             }
01911 
01912             /* For spells to work correctly, we need to record what spell
01913              * tags we've merged in with this effect.  This is used
01914              * in ok_to_put_more() to see if a spell effect is already on
01915              * the space.
01916              */
01917             if (op->stats.maxhp != tmp->stats.maxhp) {
01918 #ifdef OBJECT_DEBUG
01919                 /* This if statement should never happen - the logic above should
01920                  * have prevented it.  It is a problem, because by now its possible
01921                  * we've destroyed the spell_tags in tmp, so we can't really
01922                  * just bail out.
01923                  */
01924 
01925                 if (op->spell_tags
01926                 && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
01927                 && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
01928                     LOG(llevError, "insert_ob_in_map: Got non matching spell tags: %d != %d\n", OB_SPELL_TAG_HASH(op, tmp->stats.maxhp), tmp->stats.maxhp);
01929                 }
01930 #endif
01931                 if (!op->spell_tags)
01932                     op->spell_tags = calloc(1, SPELL_TAG_SIZE*sizeof(tag_t));
01933 
01934                 OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
01935             }
01936 
01937             statistics.spell_merges++;
01938             op->speed_left = MAX(op->speed_left, tmp->speed_left);
01939 
01940             if (tmp->duration != op->duration) {
01941                 /* We need to use tmp_dam here because otherwise the
01942                  * calculations can overflow the size of stats.dam.
01943                  */
01944                 int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
01945                               op->stats.dam*(op->duration+1);
01946 
01947                 op->duration = MAX(op->duration, tmp->duration);
01948                 tmp_dam /= (op->duration+1);
01949                 op->stats.dam = tmp_dam+1;
01950             } else {
01951                 /* in this case, duration is the same, so simply adding
01952                  * up damage works.
01953                  */
01954                 op->stats.dam += tmp->stats.dam;
01955             }
01956 
01957             remove_ob(tmp);
01958             free_object(tmp);
01959         }
01960     }
01961 }
01962 
01992 object *insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag) {
01993     object *tmp, *top, *floor = NULL;
01994     sint16 x, y;
01995 
01996     if (QUERY_FLAG(op, FLAG_FREED)) {
01997         LOG(llevError, "Trying to insert freed object!\n");
01998         return NULL;
01999     }
02000     if (m == NULL) {
02001         StringBuffer *sb;
02002         char *diff;
02003 
02004         sb = stringbuffer_new();
02005         dump_object(op, sb);
02006         diff = stringbuffer_finish(sb);
02007         LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
02008         free(diff);
02009         return op;
02010     }
02011     if (out_of_map(m, op->x, op->y)) {
02012         StringBuffer *sb;
02013         char *diff;
02014 
02015         sb = stringbuffer_new();
02016         dump_object(op, sb);
02017         diff = stringbuffer_finish(sb);
02018         LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
02019         free(diff);
02020 #ifdef MANY_CORES
02021         /* Better to catch this here, as otherwise the next use of this object
02022          * is likely to cause a crash.  Better to find out where it is getting
02023          * improperly inserted.
02024          */
02025         abort();
02026 #endif
02027         return op;
02028     }
02029     if (!QUERY_FLAG(op, FLAG_REMOVED)) {
02030         StringBuffer *sb;
02031         char *diff;
02032 
02033         sb = stringbuffer_new();
02034         dump_object(op, sb);
02035         diff = stringbuffer_finish(sb);
02036         LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
02037         free(diff);
02038         return op;
02039     }
02040     if (op->more != NULL) {
02041         /* The part may be on a different map. */
02042 
02043         object *more = op->more;
02044 
02045         /* We really need the caller to normalize coordinates - if
02046          * we set the map, that doesn't work if the location is within
02047          * a map and this is straddling an edge.  So only if coordinate
02048          * is clear wrong do we normalize it.
02049          */
02050         if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
02051             /* Debugging information so you can see the last coordinates this object had */
02052             more->ox = more->x;
02053             more->oy = more->y;
02054             more->map = get_map_from_coord(m, &more->x, &more->y);
02055         } else if (!more->map) {
02056             /* For backwards compatibility - when not dealing with tiled maps,
02057             * more->map should always point to the parent.
02058             */
02059             more->map = m;
02060         }
02061 
02062         if (insert_ob_in_map(more, more->map, originator, flag) == NULL) {
02063             if (!op->head)
02064                 LOG(llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n");
02065             return NULL;
02066         }
02067     }
02068     CLEAR_FLAG(op, FLAG_REMOVED);
02069 
02070     /* Debugging information so you can see the last coordinates this object had */
02071     op->ox = op->x;
02072     op->oy = op->y;
02073     x = op->x;
02074     y = op->y;
02075     op->map = get_map_from_coord(m, &x, &y);
02076 
02077     /* this has to be done after we translate the coordinates. */
02078     if (op->nrof
02079     && !(flag&INS_NO_MERGE)
02080     && op->type != SPELL_EFFECT) {
02081         for (tmp = GET_MAP_OB(op->map, x, y); tmp != NULL; tmp = tmp->above) {
02082             if (can_merge(op, tmp)) {
02083                 op->nrof += tmp->nrof;
02084                 remove_ob(tmp);
02085                 free_object(tmp);
02086             }
02087         }
02088     } else if (op->type == SPELL_EFFECT
02089     && !op->range
02090     && !op->other_arch
02091     && (op->speed_left+op->speed) < 0.0) {
02092         merge_spell(op, x, y);
02093     }
02094 
02095     /* Ideally, the caller figures this out.  However, it complicates a lot
02096      * of areas of callers (eg, anything that uses find_free_spot would now
02097      * need extra work
02098      */
02099     if (op->map != m) {
02100         /* coordinates should not change unless map also changes */
02101         op->x = x;
02102         op->y = y;
02103     }
02104 
02105     if (op->type != LAMP)
02106         /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
02107          Other objects just get unapplied, since the container "drops" them. */
02108         CLEAR_FLAG(op, FLAG_APPLIED);
02109     CLEAR_FLAG(op, FLAG_INV_LOCKED);
02110     if (!QUERY_FLAG(op, FLAG_ALIVE))
02111         CLEAR_FLAG(op, FLAG_NO_STEAL);
02112 
02113     /* In many places, a player is passed as the originator, which
02114      * is fine.  However, if the player is on a transport, they are not
02115      * actually on the map, so we can't use them for the linked pointers,
02116      * nor should the walk on function below use them either.
02117      */
02118     if (originator && originator->contr && originator->contr->transport)
02119         originator = originator->contr->transport;
02120 
02121     if (flag&INS_BELOW_ORIGINATOR) {
02122         if (originator->map != op->map
02123         || originator->x != op->x
02124         || originator->y != op->y) {
02125             LOG(llevError, "insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
02126             abort();
02127         }
02128         op->above = originator;
02129         op->below = originator->below;
02130         if (op->below)
02131             op->below->above = op;
02132         else
02133             SET_MAP_OB(op->map, op->x, op->y, op);
02134         /* since *below *originator, no need to update top */
02135         originator->below = op;
02136     } else {
02137         /* If there are other objects, then */
02138         /* This test is incorrect i think, as ins_above_floor_only needs the floor variable
02139         if ((!(flag&INS_MAP_LOAD)) && ((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) {
02140         */
02141         if (((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) {
02142             object *last = NULL;
02143 
02144             /*
02145              * If there are multiple objects on this space, we do some trickier handling.
02146              * We've already dealt with merging if appropriate.
02147              * Generally, we want to put the new object on top. But if
02148              * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
02149              * floor, we want to insert above that and no further.
02150              * Also, if there are spell objects on this space, we stop processing
02151              * once we get to them.  This reduces the need to traverse over all of
02152              * them when adding another one - this saves quite a bit of cpu time
02153              * when lots of spells are cast in one area.  Currently, it is presumed
02154              * that flying non pickable objects are spell objects.
02155              */
02156 
02157             while (top != NULL) {
02158                 if (QUERY_FLAG(top, FLAG_IS_FLOOR)
02159                 || QUERY_FLAG(top, FLAG_OVERLAY_FLOOR))
02160                     floor = top;
02161 
02162                 if (QUERY_FLAG(top, FLAG_NO_PICK)
02163                 && (top->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
02164                 && !QUERY_FLAG(top, FLAG_IS_FLOOR)) {
02165                     /* We insert above top, so we want this object below this */
02166                     top = top->below;
02167                     break;
02168                 }
02169                 last = top;
02170                 top = top->above;
02171             }
02172             /* Don't want top to be NULL, so set it to the last valid object */
02173             top = last;
02174 
02175             /* We let update_position deal with figuring out what the space
02176              * looks like instead of lots of conditions here.
02177              * makes things faster, and effectively the same result.
02178              */
02179 
02180         } /* If objects on this space */
02181         if (flag&INS_MAP_LOAD)
02182             top = GET_MAP_TOP(op->map, op->x, op->y);
02183         if (flag&INS_ABOVE_FLOOR_ONLY)
02184             top = floor;
02185 
02186         /* Top is the object that our object (op) is going to get inserted above. */
02187 
02188         /* First object on this space */
02189         if (!top) {
02190             op->above = GET_MAP_OB(op->map, op->x, op->y);
02191             if (op->above)
02192                 op->above->below = op;
02193             op->below = NULL;
02194             SET_MAP_OB(op->map, op->x, op->y, op);
02195         } else { /* get inserted into the stack above top */
02196             op->above = top->above;
02197             if (op->above)
02198                 op->above->below = op;
02199             op->below = top;
02200             top->above = op;
02201         }
02202         if (op->above == NULL)
02203             SET_MAP_TOP(op->map, op->x, op->y, op);
02204     } /* else not INS_BELOW_ORIGINATOR */
02205 
02206     if (op->type == PLAYER)
02207         op->contr->do_los = 1;
02208 
02209     /* If we have a floor, we know the player, if any, will be above
02210      * it, so save a few ticks and start from there.
02211      */
02212     if (!(flag&INS_MAP_LOAD))
02213         for (tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
02214             if (tmp->type == PLAYER)
02215                 tmp->contr->socket.update_look = 1;
02216         }
02217 
02218     /* If this object glows, it may affect lighting conditions that are
02219      * visible to others on this map.  But update_all_los is really
02220      * an inefficient way to do this, as it means los for all players
02221      * on the map will get recalculated.  The players could very well
02222      * be far away from this change and not affected in any way -
02223      * this should get redone to only look for players within range,
02224      * or just updating the P_NEED_UPDATE for spaces within this area
02225      * of effect may be sufficient.
02226      */
02227     if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
02228         update_all_los(op->map, op->x, op->y);
02229 
02230 
02231     /* updates flags (blocked, alive, no magic, etc) for this map space */
02232     update_object(op, UP_OBJ_INSERT);
02233 
02234     if (op->contr && !op->contr->hidden)
02235         op->map->players++;
02236 
02237     /* Don't know if moving this to the end will break anything.  However,
02238      * we want to have update_look set above before calling this.
02239      *
02240      * check_move_on() must be after this because code called from
02241      * check_move_on() depends on correct map flags (so functions like
02242      * blocked() and wall() work properly), and these flags are updated by
02243      * update_object().
02244      */
02245 
02246     /* if this is not the head or flag has been passed, don't check walk on status */
02247 
02248     if (!(flag&INS_NO_WALK_ON) && !op->head) {
02249         if (check_move_on(op, originator))
02250             return NULL;
02251 
02252         /* If we are a multi part object, lets work our way through the check
02253          * walk on's.
02254          */
02255         for (tmp = op->more; tmp != NULL; tmp = tmp->more)
02256             if (check_move_on(tmp, originator))
02257                 return NULL;
02258     }
02259     return op;
02260 }
02261 
02271 void replace_insert_ob_in_map(const char *arch_string, object *op) {
02272     object *tmp;
02273     object *tmp1;
02274 
02275     /* first search for itself and remove any old instances */
02276     for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp1) {
02277         tmp1 = tmp->above;
02278         if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
02279             remove_ob(tmp);
02280             free_object(tmp);
02281         }
02282     }
02283 
02284     tmp1 = arch_to_object(find_archetype(arch_string));
02285 
02286     tmp1->x = op->x;
02287     tmp1->y = op->y;
02288     insert_ob_in_map(tmp1, op->map, op, INS_BELOW_ORIGINATOR);
02289 }
02290 
02313 object *get_split_ob(object *orig_ob, uint32 nr, char *err, size_t size) {
02314     object *newob;
02315 
02316     if (orig_ob->nrof < nr) {
02317         /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
02318         if (err)
02319             snprintf(err, size, "There are only %u %ss.", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name);
02320         else
02321             LOG(llevDebug, "There are only %u %ss.\n", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name);
02322         return NULL;
02323     }
02324     newob = object_create_clone(orig_ob);
02325     newob->nrof = nr;
02326     decrease_ob_nr(orig_ob, nr);
02327 
02328     return newob;
02329 }
02330 
02345 object *decrease_ob_nr(object *op, uint32 i) {
02346     object *tmp;
02347     player *pl;
02348 
02349     if (i == 0)   /* objects with op->nrof require this check */
02350         return op;
02351 
02352     if (i > op->nrof)
02353         i = op->nrof;
02354 
02355     if (QUERY_FLAG(op, FLAG_REMOVED)) {
02356         op->nrof -= i;
02357     } else if (op->env != NULL) {
02358         /* is this object in the players inventory, or sub container
02359          * therein?
02360          */
02361         tmp = get_player_container(op->env);
02362         /* nope.  Is this a container the player has opened?
02363          * If so, set tmp to that player.
02364          * IMO, searching through all the players will mostly
02365          * likely be quicker than following op->env to the map,
02366          * and then searching the map for a player.
02367          */
02368         if (!tmp) {
02369             for (pl = first_player; pl; pl = pl->next)
02370                 if (pl->ob->container == op->env)
02371                     break;
02372             if (pl)
02373                 tmp = pl->ob;
02374             else
02375                 tmp = NULL;
02376         }
02377 
02378         if (i < op->nrof) {
02379             sub_weight(op->env, op->weight*i);
02380             op->nrof -= i;
02381             if (tmp) {
02382                 esrv_update_item(UPD_NROF, tmp, op);
02383             }
02384         } else {
02385             remove_ob(op);
02386             op->nrof = 0;
02387         }
02388     } else {
02389         /* On a map. */
02390         if (i < op->nrof) {
02391             object *pl;
02392             op->nrof -= i;
02393 
02394             pl = GET_MAP_OB(op->map, op->x, op->y);
02395             while (pl && !pl->contr)
02396                 pl = pl->above;
02397             if (pl && pl->contr)
02398                 pl->contr->socket.update_look = 1;
02399         } else {
02400             remove_ob(op);
02401             op->nrof = 0;
02402         }
02403     }
02404 
02405     if (op->nrof) {
02406         return op;
02407     } else {
02408         free_object(op);
02409         return NULL;
02410     }
02411 }
02412 
02423 static void increase_ob_nr(object *op, uint32 i) {
02424     object *tmp;
02425     player *pl;
02426 
02427     if (i == 0)   /* objects with op->nrof require this check */
02428         return;
02429 
02430     if (QUERY_FLAG(op, FLAG_REMOVED)) {
02431         op->nrof += i;
02432     } else if (op->env != NULL) {
02433         /* is this object in the players inventory, or sub container
02434          * therein?
02435          */
02436         tmp = get_player_container(op->env);
02437         /* nope.  Is this a container the player has opened?
02438          * If so, set tmp to that player.
02439          * IMO, searching through all the players will mostly
02440          * likely be quicker than following op->env to the map,
02441          * and then searching the map for a player.
02442          */
02443         if (!tmp) {
02444             for (pl = first_player; pl; pl = pl->next)
02445                 if (pl->ob->container == op->env)
02446                     break;
02447             if (pl)
02448                 tmp = pl->ob;
02449             else
02450                 tmp = NULL;
02451         }
02452 
02453         add_weight(op->env, op->weight*i);
02454         op->nrof += i;
02455         if (tmp) {
02456             esrv_update_item(UPD_NROF, tmp, op);
02457         }
02458     } else {
02459         /* On a map. */
02460         object *pl;
02461 
02462         op->nrof += i;
02463 
02464         pl = GET_MAP_OB(op->map, op->x, op->y);
02465         while (pl && !pl->contr)
02466             pl = pl->above;
02467         if (pl && pl->contr)
02468             pl->contr->socket.update_look = 1;
02469     }
02470 }
02471 
02486 void add_weight(object *op, signed long weight) {
02487     while (op != NULL) {
02488         if (op->type == CONTAINER) {
02489             weight = (signed long)(weight*(100-op->stats.Str)/100);
02490         }
02491         op->carrying += weight;
02492         op = op->env;
02493     }
02494 }
02495 
02510 object *insert_ob_in_ob(object *op, object *where) {
02511     object *tmp, *otmp;
02512 
02513     if (!QUERY_FLAG(op, FLAG_REMOVED)) {
02514         StringBuffer *sb;
02515         char *diff;
02516 
02517         sb = stringbuffer_new();
02518         dump_object(op, sb);
02519         diff = stringbuffer_finish(sb);
02520         LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
02521         free(diff);
02522         return op;
02523     }
02524 
02525     if (where == NULL) {
02526         StringBuffer *sb;
02527         char *diff;
02528 
02529         sb = stringbuffer_new();
02530         dump_object(op, sb);
02531         diff = stringbuffer_finish(sb);
02532         LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
02533         free(diff);
02534         return op;
02535     }
02536     if (where->head) {
02537         LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
02538         where = where->head;
02539     }
02540     if (op->more) {
02541         LOG(llevError, "Tried to insert multipart object %s (%d)\n", op->name, op->count);
02542         return op;
02543     }
02544     CLEAR_FLAG(op, FLAG_OBJ_ORIGINAL);
02545     CLEAR_FLAG(op, FLAG_REMOVED);
02546     if (op->nrof) {
02547         for (tmp = where->inv; tmp != NULL; tmp = tmp->below)
02548             if (can_merge(tmp, op)) {
02549                 /* return the original object and remove inserted object
02550                  * (client needs the original object) */
02551                 increase_ob_nr(tmp, op->nrof);
02552                 SET_FLAG(op, FLAG_REMOVED);
02553                 free_object(op); /* free the inserted object */
02554                 return tmp;
02555             }
02556 
02557         /* the item couldn't merge. */
02558         add_weight(where, op->weight*op->nrof);
02559     } else
02560         add_weight(where, (op->weight+op->carrying));
02561 
02562     op->map = NULL;
02563     op->env = where;
02564     op->above = NULL;
02565     op->below = NULL;
02566     op->x = 0,
02567     op->y = 0;
02568     op->ox = 0,
02569     op->oy = 0;
02570 
02571     /* Client has no idea of ordering so lets not bother ordering it here.
02572      * It sure simplifies this function...
02573      */
02574     if (where->inv == NULL)
02575         where->inv = op;
02576     else {
02577         op->below = where->inv;
02578         op->below->above = op;
02579         where->inv = op;
02580     }
02581 
02582     /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
02583      * is looking into. */
02584     if (where->contr != NULL)
02585         esrv_send_item(where, op);
02586     else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
02587         object *pl = NULL;
02588 
02589         if (op->env->env && op->env->env->contr)
02590             /* Container is in player's inventory. */
02591             pl = op->env->env;
02592         else if (op->env->map) {
02593             /* Container on map, look above for player. */
02594             object *above = op->env->above;
02595 
02596             while (above && !above->contr)
02597                 above = above->above;
02598             if (above)
02599                 pl = above;
02600         }
02601         if (pl)
02602             esrv_send_item(pl, op);
02603     }
02604 
02605     otmp = get_player_container(where);
02606     if (otmp && otmp->contr != NULL) {
02607         if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
02608         && (QUERY_FLAG(op, FLAG_APPLIED) || (op->type == SKILL) || (op->glow_radius != 0)))
02609             /* fix_object will only consider applied items, or skills, or items with a glow radius.
02610                thus no need to call it if our object hasn't that. */
02611             fix_object(otmp);
02612     }
02613 
02614     /* reset the light list and los of the players on the map */
02615     if ((op->glow_radius != 0) && where->map) {
02616 #ifdef DEBUG_LIGHTS
02617         LOG(llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n", op->name);
02618 #endif /* DEBUG_LIGHTS */
02619         if (MAP_DARKNESS(where->map)) {
02620             SET_MAP_FLAGS(where->map, where->x, where->y,  P_NEED_UPDATE);
02621             update_position(where->map, where->x, where->y);
02622             update_all_los(where->map, where->x, where->y);
02623         }
02624     }
02625 
02626     return op;
02627 }
02628 
02651 int check_move_on(object *op, object *originator) {
02652     object *tmp;
02653     tag_t tag;
02654     mapstruct *m = op->map;
02655     int x = op->x, y = op->y;
02656     MoveType move_on, move_slow, move_block;
02657 
02658     if (QUERY_FLAG(op, FLAG_NO_APPLY))
02659         return 0;
02660 
02661     tag = op->count;
02662 
02663     move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
02664     move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
02665     move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
02666 
02667     /* if nothing on this space will slow op down or be applied,
02668      * no need to do checking below.    have to make sure move_type
02669      * is set, as lots of objects don't have it set - we treat that
02670      * as walking.
02671      */
02672     if (op->move_type
02673     && !(op->move_type&move_on)
02674     && !(op->move_type&move_slow))
02675         return 0;
02676 
02677     /* This is basically inverse logic of that below - basically,
02678      * if the object can avoid the move on or slow move, they do so,
02679      * but can't do it if the alternate movement they are using is
02680      * blocked.  Logic on this seems confusing, but does seem correct.
02681      */
02682     if ((op->move_type&~move_on&~move_block) != 0
02683     && (op->move_type&~move_slow&~move_block) != 0)
02684         return 0;
02685 
02686     /* The objects have to be checked from top to bottom.
02687      * Hence, we first go to the top:
02688      */
02689 
02690     for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL && tmp->above != NULL; tmp = tmp->above) {
02691         /* Trim the search when we find the first other spell effect
02692          * this helps performance so that if a space has 50 spell objects,
02693          * we don't need to check all of them.
02694          */
02695         if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
02696             break;
02697     }
02698     for (; tmp != NULL; tmp = tmp->below) {
02699         if (tmp == op)
02700             continue;    /* Can't apply yourself */
02701 
02702         /* Check to see if one of the movement types should be slowed down.
02703          * Second check makes sure that the movement types not being slowed
02704          * (~slow_move) is not blocked on this space - just because the
02705          * space doesn't slow down swimming (for example), if you can't actually
02706          * swim on that space, can't use it to avoid the penalty.
02707          */
02708         if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
02709             if ((!op->move_type && tmp->move_slow&MOVE_WALK)
02710             || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
02711                 float diff;
02712 
02713                 diff = tmp->move_slow_penalty*FABS(op->speed);
02714                 if (op->type == PLAYER) {
02715                     if ((QUERY_FLAG(tmp, FLAG_IS_HILLY) && find_skill_by_number(op, SK_CLIMBING))
02716                     || (QUERY_FLAG(tmp, FLAG_IS_WOODED) && find_skill_by_number(op, SK_WOODSMAN))) {
02717                         diff /= 4.0;
02718                     }
02719                 }
02720                 op->speed_left -= diff;
02721             }
02722         }
02723 
02724         /* Basically same logic as above, except now for actual apply. */
02725         if ((!op->move_type && tmp->move_on&MOVE_WALK)
02726         || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
02727 
02728             ob_move_on(tmp, op, originator);
02729             if (was_destroyed(op, tag))
02730                 return 1;
02731 
02732             /* what the person/creature stepped onto has moved the object
02733              * someplace new.  Don't process any further - if we did,
02734              * have a feeling strange problems would result.
02735              */
02736             if (op->map != m || op->x != x || op->y != y)
02737                 return 0;
02738         }
02739     }
02740     return 0;
02741 }
02742 
02755 object *present_arch(const archetype *at, mapstruct *m, int x, int y) {
02756     object *tmp;
02757 
02758     if (m == NULL || out_of_map(m, x, y)) {
02759         LOG(llevError, "Present_arch called outside map.\n");
02760         return NULL;
02761     }
02762 
02763     for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
02764         if (tmp->arch == at)
02765             return tmp;
02766     return NULL;
02767 }
02768 
02782 object *present(uint8 type, mapstruct *m, int x, int y) {
02783     object *tmp;
02784 
02785     if (out_of_map(m, x, y)) {
02786         LOG(llevError, "Present called outside map.\n");
02787         return NULL;
02788     }
02789 
02790     for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
02791         if (tmp->type == type)
02792             return tmp;
02793     return NULL;
02794 }
02795 
02806 object *present_in_ob(uint8 type, const object *op) {
02807     object *tmp;
02808 
02809     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
02810         if (tmp->type == type)
02811             return tmp;
02812     return NULL;
02813 }
02814 
02840 object *present_in_ob_by_name(int type, const char *str, const object *op) {
02841     object *tmp;
02842 
02843     for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
02844         if ((type == -1 || tmp->type == type) && (!strcmp(str, tmp->name)))
02845             return tmp;
02846     }
02847     return NULL;
02848 }
02849 
02859 object *present_arch_in_ob(const archetype *at, const object *op)  {
02860     object *tmp;
02861 
02862     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
02863         if (tmp->arch == at)
02864             return tmp;
02865     return NULL;
02866 }
02867 
02876 void flag_inv(object*op, int flag) {
02877     object *tmp;
02878 
02879     if (op->inv)
02880         for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
02881             SET_FLAG(tmp, flag);
02882             flag_inv(tmp, flag);
02883         }
02884 }
02885 
02894 void unflag_inv(object*op, int flag) {
02895     object *tmp;
02896 
02897     if (op->inv)
02898         for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
02899             CLEAR_FLAG(tmp, flag);
02900             unflag_inv(tmp, flag);
02901         }
02902 }
02903 
02913 void set_cheat(object *op) {
02914     SET_FLAG(op, FLAG_WAS_WIZ);
02915     flag_inv(op, FLAG_WAS_WIZ);
02916 }
02917 
02935 int find_multi_free_spot_around(object *ob, object *gen, int *hx, int *hy) {
02936     int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
02937     int freecount = 0;
02938 
02939     if (ob->head)
02940         ob = ob->head;
02941 
02942     get_multi_size(ob, &sx, &sy, &sx2, &sy2);
02943     get_multi_size(gen, &genx, &geny, &genx2, &geny2);
02944     /*
02945      * sx and sy are now the coords of the bottom right corner of ob relative to the head.
02946      * genx and geny are now the coords of the bottom right corner of gen relative to the head.
02947      * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
02948      * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
02949      */
02950 
02951     sx++;
02952     sy++;
02953     genx++;
02954     geny++;
02955     /*
02956      * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
02957      * the head.
02958      */
02959 
02960     ix = gen->x-sx-genx2;
02961     iy = gen->y-sy-geny2;
02962     sx += genx+sx2;
02963     sy += geny+sy2;
02964     /*
02965      * ix and iy are the map coords of the top left square where the head of ob could possibly
02966      * be placed. sx and sy are now the size of the square to search for placement of the head
02967      * relative to ix and iy.
02968      */
02969 
02970     /*
02971      * Loop around the square of possible positions for the head of ob object:
02972      */
02973     for (i = 0; i < (sx+sx+sy+sy); i++) {
02974         if (i <= sx) {
02975             nx = i+ix;
02976             ny = iy;
02977         } else if (i <= (sx+sy)) {
02978             nx = ix+sx;
02979             ny = iy+i-sx;
02980         } else if (i <= (sx+sy+sx)) {
02981             nx = ix+sx-(i-(sx+sy));
02982             ny = iy+sy;
02983         } else {
02984             nx = ix;
02985             ny = iy+sy-(i-(sx+sy+sx));
02986         }
02987         /* Check if the spot is free. */
02988         flag = ob_blocked(ob, gen->map, nx, ny);
02989         if (!flag) {
02990             freecount++;
02991         }
02992     }
02993     /* If no free spaces, return. */
02994     if (!freecount)
02995         return -1;
02996 
02997     /* Choose a random valid position */
02998     freecount = RANDOM()%freecount;
02999     for (i = 0; i < (sx+sx+sy+sy); i++) {
03000         if (i <= sx) {
03001             nx = i+ix;
03002             ny = iy;
03003         } else if (i <= (sx+sy)) {
03004             nx = ix+sx;
03005             ny = iy+i-sx;
03006         } else if (i <= (sx+sy+sx)) {
03007             nx = ix+sx-(i-(sx+sy));
03008             ny = iy+sy;
03009         } else {
03010             nx = ix;
03011             ny = iy+sy-(i-(sx+sy+sx));
03012         }
03013 
03014         /* Make sure it's within map. */
03015         if (nx < 0 || nx >= MAP_WIDTH(gen->map)
03016         || ny < 0 || ny >= MAP_HEIGHT(gen->map))
03017             continue;
03018 
03019         /* Check if the spot is free.*/
03020         flag = ob_blocked(ob, gen->map, nx, ny);
03021         if (!flag) {
03022             freecount--;
03023             if (freecount <= 0) {
03024                 *hx = nx;
03025                 *hy = ny;
03026                 return 0;
03027             }
03028         }
03029     }
03030     return -1;
03031 }
03032 
03052 int find_multi_free_spot_within_radius(object *ob, object *gen, int *hx, int *hy) {
03053     int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
03054     sint8 x, y, radius;
03055     int freecount = 0, freecountstop = 0;
03056     const char *value;
03057     sint8 *x_array;
03058     sint8 *y_array;
03059 
03060     /* If radius is not set, default to 1 */
03061     value = get_ob_key_value(gen, "generator_radius");
03062     if (value) {
03063         radius = (sint8)strtol((char *)value, NULL, 10);
03064         if (radius < 1) {
03065             radius = 1;
03066         }
03067     } else {
03068         radius = 1;
03069     }
03070 
03071     if (ob->head)
03072         ob = ob->head;
03073 
03074     get_multi_size(ob, &sx, &sy, &sx2, &sy2);
03075     get_multi_size(gen, &genx, &geny, &genx2, &geny2);
03076     /*
03077      * sx and sy are now the coords of the bottom right corner
03078      * of ob relative to the head.
03079      * genx and geny are now the coords of the bottom right corner
03080      * of gen relative to the head.
03081      * sx2 and sy2 are now the coords of the head of ob relative
03082      * to the top left corner.
03083      * genx2 and geny2 are now the coords of the head of gen relative
03084      * to the top left corner.
03085      */
03086 
03087     sx++;
03088     sy++;
03089     genx++;
03090     geny++;
03091     /*
03092      * sx, sy, genx, and geny, are now the size of the object,
03093      * excluding parts left and above the head.
03094      */
03095 
03096     ix = gen->x-sx-genx2-radius+1;
03097     iy = gen->y-sy-geny2-radius+1;
03098     sx += genx+sx2+radius*2-1;
03099     sy += geny+sy2+radius*2-1;
03100 
03101     /*
03102      * ix and iy are the map coords of the top left square where
03103      * the head of ob could possibly be placed. sx and sy are now
03104      * the size of the square to search for placement of the head
03105      * relative to ix and iy.
03106      */
03107 
03108     /* Create arrays large enough to hold free space coordinates */
03109     x_array = malloc(sx*sy*sizeof(sint8));
03110     y_array = malloc(sx*sy*sizeof(sint8));
03111 
03112     /*
03113      * Loop through the area of possible positions for the head of ob object:
03114      */
03115     for (x = 0; x < sx; x++) {
03116         for (y = 0; y < sy; y++) {
03117             nx = ix+x;
03118             ny = iy+y;
03119 
03120 
03121             /* Make sure it's within map. */
03122             if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
03123                 continue;
03124             }
03125 
03126             /* Check if the spot is free. */
03127             flag = ob_blocked(ob, gen->map, nx, ny);
03128             if (!flag) {
03129                 x_array[freecount] = nx;
03130                 y_array[freecount] = ny;
03131                 freecount++;
03132             }
03133         }
03134     }
03135     /* If no free spaces, return. */
03136     if (!freecount) {
03137         free(x_array);
03138         free(y_array);
03139         return -1;
03140     }
03141 
03142     /* Choose a random valid position */
03143     freecountstop = RANDOM()%freecount;
03144     for (i = 0; i < freecount; i++) {
03145         nx = x_array[i];
03146         ny = y_array[i];
03147 
03148         /* Check if the spot is free.*/
03149         flag = ob_blocked(ob, gen->map, nx, ny);
03150         if (!flag) {
03151             freecountstop--;
03152             if (freecountstop <= 0) {
03153                 *hx = nx;
03154                 *hy = ny;
03155                 free(x_array);
03156                 free(y_array);
03157                 return 0;
03158             }
03159         }
03160     }
03161     free(x_array);
03162     free(y_array);
03163     return -1;
03164 }
03165 
03200 int find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
03201     int i, index = 0, flag;
03202     static int altern[SIZEOFFREE];
03203 
03204     for (i = start; i < stop; i++) {
03205         flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
03206         if (!flag)
03207             altern[index++] = i;
03208 
03209         /* Basically, if we find a wall on a space, we cut down the search size.
03210          * In this way, we won't return spaces that are on another side of a wall.
03211          * This mostly work, but it cuts down the search size in all directions -
03212          * if the space being examined only has a wall to the north and empty
03213          * spaces in all the other directions, this will reduce the search space
03214          * to only the spaces immediately surrounding the target area, and
03215          * won't look 2 spaces south of the target space.
03216          */
03217         else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
03218             stop = maxfree[i];
03219     }
03220     if (!index)
03221         return -1;
03222     return altern[RANDOM()%index];
03223 }
03224 
03240 int find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
03241     int i;
03242 
03243     for (i = 0; i < SIZEOFFREE; i++) {
03244         if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
03245             return i;
03246     }
03247     return -1;
03248 }
03249 
03259 static void permute(int *arr, int begin, int end) {
03260     int i, j, tmp, len;
03261 
03262     len = end-begin;
03263     for (i = begin; i < end; i++) {
03264         j = begin+RANDOM()%len;
03265 
03266         tmp = arr[i];
03267         arr[i] = arr[j];
03268         arr[j] = tmp;
03269     }
03270 }
03271 
03283 void get_search_arr(int *search_arr) {
03284     int i;
03285 
03286     for (i = 0; i < SIZEOFFREE; i++) {
03287         search_arr[i] = i;
03288     }
03289 
03290     permute(search_arr, 1, SIZEOFFREE1+1);
03291     permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
03292     permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
03293 }
03294 
03313 int find_dir(mapstruct *m, int x, int y, object *exclude) {
03314     int i, max = SIZEOFFREE, mflags;
03315     sint16 nx, ny;
03316     object *tmp;
03317     mapstruct *mp;
03318     MoveType blocked, move_type;
03319 
03320     if (exclude && exclude->head) {
03321         exclude = exclude->head;
03322         move_type = exclude->move_type;
03323     } else {
03324         /* If we don't have anything, presume it can use all movement types. */
03325         move_type = MOVE_ALL;
03326     }
03327 
03328     for (i = 1; i < max; i++) {
03329         mp = m;
03330         nx = x+freearr_x[i];
03331         ny = y+freearr_y[i];
03332 
03333         mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
03334         if (mflags&P_OUT_OF_MAP) {
03335             max = maxfree[i];
03336         } else {
03337             blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny);
03338 
03339             if ((move_type&blocked) == move_type) {
03340                 max = maxfree[i];
03341             } else if (mflags&P_IS_ALIVE) {
03342                 for (tmp = GET_MAP_OB(mp, nx, ny); tmp != NULL; tmp = tmp->above) {
03343                     if ((QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
03344                     && (tmp != exclude ||(tmp->head && tmp->head != exclude))) {
03345                         break;
03346                     }
03347                 }
03348                 if (tmp) {
03349                     return freedir[i];
03350                 }
03351             }
03352         }
03353     }
03354     return 0;
03355 }
03356 
03364 int distance(const object *ob1, const object *ob2) {
03365     int i;
03366 
03367     i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
03368         (ob1->y-ob2->y)*(ob1->y-ob2->y);
03369     return i;
03370 }
03371 
03380 int find_dir_2(int x, int y) {
03381     int q;
03382 
03383     if (!y)
03384         q = -300*x;
03385     else
03386         q = x*100/y;
03387     if (y > 0) {
03388         if (q < -242)
03389             return 3;
03390         if (q < -41)
03391             return 2;
03392         if (q < 41)
03393             return 1;
03394         if (q < 242)
03395             return 8;
03396         return 7;
03397     }
03398     if (q < -242)
03399         return 7;
03400     if (q < -41)
03401         return 6;
03402     if (q < 41)
03403         return 5;
03404     if (q < 242)
03405         return 4;
03406     return 3;
03407 }
03408 
03417 int absdir(int d) {
03418     while (d < 1)
03419         d += 8;
03420     while (d > 8)
03421         d -= 8;
03422     return d;
03423 }
03424 
03434 int dirdiff(int dir1, int dir2) {
03435     int d;
03436 
03437     d = abs(dir1-dir2);
03438     if (d > 4)
03439         d = 8-d;
03440     return d;
03441 }
03442 
03454 static const int reduction_dir[SIZEOFFREE][3] = {
03455     {  0,  0,  0 }, /* 0 */
03456     {  0,  0,  0 }, /* 1 */
03457     {  0,  0,  0 }, /* 2 */
03458     {  0,  0,  0 }, /* 3 */
03459     {  0,  0,  0 }, /* 4 */
03460     {  0,  0,  0 }, /* 5 */
03461     {  0,  0,  0 }, /* 6 */
03462     {  0,  0,  0 }, /* 7 */
03463     {  0,  0,  0 }, /* 8 */
03464     {  8,  1,  2 }, /* 9 */
03465     {  1,  2, -1 }, /* 10 */
03466     {  2, 10, 12 }, /* 11 */
03467     {  2,  3, -1 }, /* 12 */
03468     {  2,  3,  4 }, /* 13 */
03469     {  3,  4, -1 }, /* 14 */
03470     {  4, 14, 16 }, /* 15 */
03471     {  5,  4, -1 }, /* 16 */
03472     {  4,  5,  6 }, /* 17 */
03473     {  6,  5, -1 }, /* 18 */
03474     {  6, 20, 18 }, /* 19 */
03475     {  7,  6, -1 }, /* 20 */
03476     {  6,  7,  8 }, /* 21 */
03477     {  7,  8, -1 }, /* 22 */
03478     {  8, 22, 24 }, /* 23 */
03479     {  8,  1, -1 }, /* 24 */
03480     { 24,  9, 10 }, /* 25 */
03481     {  9, 10, -1 }, /* 26 */
03482     { 10, 11, -1 }, /* 27 */
03483     { 27, 11, 29 }, /* 28 */
03484     { 11, 12, -1 }, /* 29 */
03485     { 12, 13, -1 }, /* 30 */
03486     { 12, 13, 14 }, /* 31 */
03487     { 13, 14, -1 }, /* 32 */
03488     { 14, 15, -1 }, /* 33 */
03489     { 33, 15, 35 }, /* 34 */
03490     { 16, 15, -1 }, /* 35 */
03491     { 17, 16, -1 }, /* 36 */
03492     { 18, 17, 16 }, /* 37 */
03493     { 18, 17, -1 }, /* 38 */
03494     { 18, 19, -1 }, /* 39 */
03495     { 41, 19, 39 }, /* 40 */
03496     { 19, 20, -1 }, /* 41 */
03497     { 20, 21, -1 }, /* 42 */
03498     { 20, 21, 22 }, /* 43 */
03499     { 21, 22, -1 }, /* 44 */
03500     { 23, 22, -1 }, /* 45 */
03501     { 45, 47, 23 }, /* 46 */
03502     { 23, 24, -1 }, /* 47 */
03503     { 24,  9, -1 }  /* 48 */
03504 };
03505 
03524 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
03525     sint16 dx, dy;
03526     int mflags;
03527 
03528     if (dir < 0)
03529         return 0; /* exit condition:  invalid direction */
03530 
03531     dx = x+freearr_x[dir];
03532     dy = y+freearr_y[dir];
03533 
03534     mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
03535 
03536     /* This functional arguably was incorrect before - it was
03537      * checking for P_WALL - that was basically seeing if
03538      * we could move to the monster - this is being more
03539      * literal on if we can see it.  To know if we can actually
03540      * move to the monster, we'd need the monster passed in or
03541      * at least its move type.
03542      */
03543     if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
03544         return 0;
03545 
03546     /* yes, can see. */
03547     if (dir < 9)
03548         return 1;
03549     return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
03550            can_see_monsterP(m, x, y, reduction_dir[dir][1])|
03551            can_see_monsterP(m, x, y, reduction_dir[dir][2]);
03552 }
03553 
03569 int can_pick(const object *who, const object *item) {
03570     /* I re-wrote this as a series of if statements
03571      * instead of a nested return (foo & bar && yaz)
03572      * - I think this is much more readable,
03573      * and likely compiler effectively optimizes it the
03574      * same.
03575      */
03576     if (item->weight <= 0)
03577         return 0;
03578     if (QUERY_FLAG(item, FLAG_NO_PICK))
03579         return 0;
03580     if (QUERY_FLAG(item, FLAG_ALIVE))
03581         return 0;
03582     if (item->invisible)
03583         return 0;
03584 
03585     /* Weight limit for monsters */
03586     if (who->type != PLAYER && item->weight > (who->weight/3))
03587         return 0;
03588 
03589     /* Can not pick up multipart objects */
03590     if (item->head || item->more)
03591         return 0;
03592 
03593     /* Everything passes, so OK to pick up */
03594     return 1;
03595 }
03596 
03608 object *object_create_clone(object *asrc) {
03609     object *dst = NULL, *tmp, *src, *part, *prev, *item;
03610 
03611     if (!asrc)
03612         return NULL;
03613     src = asrc;
03614     if (src->head)
03615         src = src->head;
03616 
03617     prev = NULL;
03618     for (part = src; part; part = part->more) {
03619         tmp = get_object();
03620         copy_object(part, tmp);
03621         tmp->x -= src->x;
03622         tmp->y -= src->y;
03623         if (!part->head) {
03624             dst = tmp;
03625             tmp->head = NULL;
03626         } else {
03627             tmp->head = dst;
03628         }
03629         tmp->more = NULL;
03630         if (prev)
03631             prev->more = tmp;
03632         prev = tmp;
03633     }
03634     /*** copy inventory ***/
03635     for (item = src->inv; item; item = item->below) {
03636         (void)insert_ob_in_ob(object_create_clone(item), dst);
03637     }
03638 
03639     return dst;
03640 }
03641 
03656 object *find_obj_by_type_subtype(const object *who, int type, int subtype) {
03657     object *tmp;
03658 
03659     for (tmp = who->inv; tmp; tmp = tmp->below)
03660         if (tmp->type == type && tmp->subtype == subtype)
03661             return tmp;
03662 
03663     return NULL;
03664 }
03665 
03676 key_value *get_ob_key_link(const object *ob, const char *key) {
03677     key_value *link;
03678 
03679     for (link = ob->key_values; link != NULL; link = link->next) {
03680         if (link->key == key) {
03681             return link;
03682         }
03683     }
03684 
03685     return NULL;
03686 }
03687 
03701 const char *get_ob_key_value(const object *op, const char *const key) {
03702     key_value *link;
03703     const char *canonical_key;
03704 
03705     canonical_key = find_string(key);
03706 
03707     if (canonical_key == NULL) {
03708         /* 1. There being a field named key on any object
03709          *    implies there'd be a shared string to find.
03710          * 2. Since there isn't, no object has this field.
03711          * 3. Therefore, *this *object doesn't have this field.
03712          */
03713         return NULL;
03714     }
03715 
03716     /* This is copied from get_ob_key_link() above -
03717      * only 4 lines, and saves the function call overhead.
03718      */
03719     for (link = op->key_values; link != NULL; link = link->next) {
03720         if (link->key == canonical_key) {
03721             return link->value;
03722         }
03723     }
03724     return NULL;
03725 }
03726 
03741 static int set_ob_key_value_s(object *op, const char *canonical_key, const char *value, int add_key) {
03742     key_value *field = NULL, *last = NULL;
03743 
03744     LOG(llevDebug, "set_ob_value_s: '%s' '%s' %d\n", canonical_key, value ? value : "null", add_key);
03745 
03746     for (field = op->key_values; field != NULL; field = field->next) {
03747         if (field->key != canonical_key) {
03748             last = field;
03749             continue;
03750         }
03751 
03752         if (field->value)
03753             FREE_AND_CLEAR_STR(field->value);
03754         if (value)
03755             field->value = add_string(value);
03756         else {
03757             /* Basically, if the archetype has this key set,
03758              * we need to store the null value so when we save
03759              * it, we save the empty value so that when we load,
03760              * we get this value back again.
03761              */
03762             if (get_ob_key_link(&op->arch->clone, canonical_key))
03763                 field->value = NULL;
03764             else {
03765                 /* Delete this link */
03766                 if (field->key)
03767                     FREE_AND_CLEAR_STR(field->key);
03768                 if (field->value)
03769                     FREE_AND_CLEAR_STR(field->value);
03770                 if (last)
03771                     last->next = field->next;
03772                 else
03773                     op->key_values = field->next;
03774                 free(field);
03775             }
03776         }
03777         return TRUE;
03778     }
03779     /* IF we get here, key doesn't exist */
03780 
03781     /* No field, we'll have to add it. */
03782 
03783     if (!add_key) {
03784         return FALSE;
03785     }
03786     /* There isn't any good reason to store a null
03787      * value in the key/value list.  If the archetype has
03788      * this key, then we should also have it, so shouldn't
03789      * be here.  If user wants to store empty strings,
03790      * should pass in ""
03791      */
03792     if (value == NULL)
03793         return TRUE;
03794 
03795     field = malloc(sizeof(key_value));
03796 
03797     field->key = add_refcount(canonical_key);
03798     field->value = add_string(value);
03799     /* Usual prepend-addition. */
03800     field->next = op->key_values;
03801     op->key_values = field;
03802 
03803     return TRUE;
03804 }
03805 
03826 int set_ob_key_value(object *op, const char *key, const char *value, int add_key) {
03827     const char *canonical_key = NULL;
03828     int floating_ref = FALSE;
03829     int ret;
03830 
03831     /* HACK This mess is to make sure set_ob_value() passes a shared string
03832      * to get_ob_key_link(), without leaving a leaked refcount.
03833      */
03834 
03835     canonical_key = find_string(key);
03836     if (canonical_key == NULL) {
03837         canonical_key = add_string(key);
03838         floating_ref = TRUE;
03839     }
03840 
03841     ret = set_ob_key_value_s(op, canonical_key, value, add_key);
03842 
03843     if (floating_ref) {
03844         free_string(canonical_key);
03845     }
03846 
03847     return ret;
03848 }
03849 
03901 int item_matched_string(object *pl, object *op, const char *name) {
03902     char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
03903     int count, retval = 0;
03904     strcpy(local_name, name);   /* strtok is destructive to name */
03905 
03906     for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
03907         while (cp[0] == ' ')
03908             ++cp;    /* get rid of spaces */
03909 
03910         /*  LOG(llevDebug, "Trying to match %s\n", cp);*/
03911         /* All is a very generic match - low match value */
03912         if (!strcmp(cp, "all"))
03913             return 1;
03914 
03915         /* unpaid is a little more specific */
03916         if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
03917             return 2;
03918         if (!strcmp(cp, "cursed")
03919         && QUERY_FLAG(op, FLAG_KNOWN_CURSED)
03920         && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
03921             return 2;
03922 
03923         if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
03924             return 2;
03925 
03926         /* Allow for things like '100 arrows' */
03927         if ((count = atoi(cp)) != 0) {
03928             cp = strchr(cp, ' ');
03929             while (cp && cp[0] == ' ')
03930                 ++cp;  /* get rid of spaces */
03931         } else {
03932             if (pl->type == PLAYER)
03933                 count = pl->contr->count;
03934             else
03935                 count = 0;
03936         }
03937 
03938         if (!cp || cp[0] == '\0' || count < 0)
03939             return 0;
03940 
03941         /* The code here should go from highest retval to lowest.  That
03942          * is because of the 'else' handling - we don't want to match on
03943          * something and set a low retval, even though it may match a higher retcal
03944          * later.  So keep it in descending order here, so we try for the best
03945          * match first, and work downward.
03946          */
03947         query_name(op, name_op, MAX_BUF);
03948         query_short_name(op, name_short, HUGE_BUF);
03949         query_base_name(op, 0, bname_s, MAX_BUF);
03950         query_base_name(op, 1, bname_p, MAX_BUF);
03951 
03952         if (!strcasecmp(cp, name_op))
03953             retval = 20;
03954         else if (!strcasecmp(cp, name_short))
03955             retval = 18;
03956         else if (!strcasecmp(cp, bname_s))
03957             retval = 16;
03958         else if (!strcasecmp(cp, bname_p))
03959             retval = 16;
03960         else if (op->custom_name && !strcasecmp(cp, op->custom_name))
03961             retval = 15;
03962         else if (!strncasecmp(cp, bname_s, strlen(cp)))
03963             retval = 14;
03964         else if (!strncasecmp(cp, bname_p, strlen(cp)))
03965             retval = 14;
03966         /* Do substring checks, so things like 'Str+1' will match.
03967          * retval of these should perhaps be lower - they are lower
03968          * then the specific strcasecmp aboves, but still higher than
03969          * some other match criteria.
03970          */
03971         else if (strstr(bname_p, cp))
03972             retval = 12;
03973         else if (strstr(bname_s, cp))
03974             retval = 12;
03975         else if (strstr(name_short, cp))
03976             retval = 12;
03977         /* Check against plural/non plural based on count. */
03978         else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
03979             retval = 6;
03980         } else if (count == 1 && !strcasecmp(op->name, cp)) {
03981             retval = 6;
03982         }
03983         /* base name matched - not bad */
03984         else if (strcasecmp(cp, op->name) == 0 && !count)
03985             retval = 4;
03986         /* Check for partial custom name, but give a real low priority */
03987         else if (op->custom_name && strstr(op->custom_name, cp))
03988             retval = 3;
03989 
03990         if (retval) {
03991             if (pl->type == PLAYER)
03992                 pl->contr->count = count;
03993             return retval;
03994         }
03995     }
03996     return 0;
03997 }
03998 
04007 void fix_multipart_object(object *tmp) {
04008     archetype *at;
04009     object *op, *last;
04010 
04011     if (!tmp->map) {
04012         LOG(llevError, "fix_multipart_object: not on a map!\n");
04013         return;
04014     }
04015 
04016     /* already multipart - don't do anything more */
04017     if (tmp->head || tmp->more)
04018         return;
04019 
04020     /* If there is nothing more to this object, this for loop
04021      * won't do anything.
04022      */
04023     for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
04024         op = arch_to_object(at);
04025 
04026         /* update x,y coordinates */
04027         op->x += tmp->x;
04028         op->y += tmp->y;
04029         op->head = tmp;
04030         op->map = tmp->map;
04031         last->more = op;
04032         if (tmp->name != op->name) {
04033             if (op->name)
04034                 free_string(op->name);
04035             op->name = add_string(tmp->name);
04036         }
04037         if (tmp->title != op->title) {
04038             if (op->title)
04039                 free_string(op->title);
04040             op->title = add_string(tmp->title);
04041         }
04042         /* we could link all the parts onto tmp, and then just
04043          * call insert_ob_in_map once, but the effect is the same,
04044          * as insert_ob_in_map will call itself with each part, and
04045          * the coding is simpler to just to it here with each part.
04046          */
04047         insert_ob_in_map(op, op->map, tmp, INS_NO_MERGE|INS_ABOVE_FLOOR_ONLY|INS_NO_WALK_ON);
04048     } /* for at = tmp->arch->more */
04049 }
04050 
04066 void get_multi_size(object *ob, int *sx, int *sy, int *hx, int *hy) {
04067     archetype *part;
04068     int maxx = 0, maxy = 0, minx = 0, miny = 0;
04069 
04070     if (ob->head)
04071         ob = ob->head;
04072     *sx = 1;
04073     *sy = 1;
04074     if (ob->arch->more) {
04075         for (part = ob->arch; part; part = part->more) {
04076             if (part->clone.x > maxx)
04077                 maxx = part->clone.x;
04078             if (part->clone.y > maxy)
04079                 maxy = part->clone.y;
04080             if (part->clone.x < minx)
04081                 minx = part->clone.x;
04082             if (part->clone.y < miny)
04083                 miny = part->clone.y;
04084         }
04085     }
04086     if (sx)
04087         *sx = maxx;
04088     if (sy)
04089         *sy = maxy;
04090     if (hx)
04091         *hx = -minx;
04092     if (hy)
04093         *hy = -miny;
04094 }