--- deliantra/server/common/object.C 2008/04/11 13:59:05 1.203 +++ deliantra/server/common/object.C 2008/04/23 07:25:54 1.218 @@ -1,7 +1,7 @@ /* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team * Copyright (©) 1992,2007 Frank Tore Johansen * @@ -21,22 +21,19 @@ * The authors can be reached via e-mail to */ -/* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects. - sub/add_weight will transcend the environment updating the carrying - variable. */ #include #include #include #include #include -#include #include #include #include UUID UUID::cur; -static const uint64 UUID_SKIP = 1<<19; +static uint64_t seq_next_save; +static const uint64 UUID_GAP = 1<<19; objectvec objects; activevec actives; @@ -83,6 +80,8 @@ sprintf (filename, "%s/uuid", settings.localdir); + seq_next_save = 0; + FILE *fp; if (!(fp = fopen (filename, "r"))) @@ -91,7 +90,7 @@ { LOG (llevInfo, "RESET uid to 1\n"); UUID::cur.seq = 0; - write_uuid (UUID_SKIP, true); + write_uuid (UUID_GAP, true); return; } @@ -111,7 +110,7 @@ LOG (llevDebug, "read UUID: %s\n", UUID::cur.c_str ()); - write_uuid (UUID_SKIP, true); + write_uuid (UUID_GAP, true); fclose (fp); } @@ -122,8 +121,12 @@ uid.seq = ++cur.seq; - if (expect_false (!(cur.seq & (UUID_SKIP - 1)))) - write_uuid (UUID_SKIP, false); + if (expect_false (cur.seq >= seq_next_save)) + { + seq_next_save = UUID::cur.seq + (UUID_GAP >> 1); + write_uuid (UUID_GAP, false); + } + return uid; } @@ -135,7 +138,7 @@ } /* Returns TRUE if every key_values in wants has a partner with the same value in has. */ -static int +static bool compare_ob_value_lists_one (const object *wants, const object *has) { key_value *wants_field; @@ -153,28 +156,22 @@ /* Look for a field in has with the same key. */ has_field = get_ob_key_link (has, wants_field->key); - if (has_field == NULL) - { - /* No field with that name. */ - return FALSE; - } + if (!has_field) + return 0; /* No field with that name. */ /* Found the matching field. */ if (has_field->value != wants_field->value) - { - /* Values don't match, so this half of the comparison is false. */ - return FALSE; - } + return 0; /* Values don't match, so this half of the comparison is false. */ /* If we get here, we found a match. Now for the next field in wants. */ } /* If we get here, every field in wants has a matching field in has. */ - return TRUE; + return 1; } /* Returns TRUE if ob1 has the same key_values as ob2. */ -static int +static bool compare_ob_value_lists (const object *ob1, const object *ob2) { /* However, there may be fields in has which aren't partnered in wants, @@ -205,16 +202,16 @@ || ob1->name != ob2->name) return 0; - //TODO: this ain't working well, use nicer and correct overflow check - /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that - * value could not be stored in a sint32 (which unfortunately sometimes is - * used to store nrof). + /* Do not merge objects if nrof would overflow. First part checks + * for unsigned overflow (2c), second part checks whether the result + * would fit into a 32 bit signed int, which is often used to hold + * nrof values. */ - if (ob1->nrof + ob2->nrof >= 1UL << 31) + if (~ob1->nrof < ob2->nrof || ob1->nrof + ob2->nrof > (1UL << 31)) return 0; /* If the objects have been identified, set the BEEN_APPLIED flag. - * This is to the comparison of the flags below will be OK. We + * This is to the comparison of the flags below will be OK. We * just can't ignore the been applied or identified flags, as they * are not equal - just if it has been identified, the been_applied * flags lose any meaning. @@ -225,14 +222,11 @@ if (QUERY_FLAG (ob2, FLAG_IDENTIFIED)) SET_FLAG (ob2, FLAG_BEEN_APPLIED); - if ((ob1->flag ^ ob2->flag).reset (FLAG_INV_LOCKED).reset (FLAG_CLIENT_SENT).any () - || ob1->arch != ob2->arch + if (ob1->arch->name != ob2->arch->name || ob1->name != ob2->name || ob1->title != ob2->title || ob1->msg != ob2->msg || ob1->weight != ob2->weight - || memcmp (&ob1->resist, &ob2->resist, sizeof (ob1->resist)) - || memcmp (&ob1->stats , &ob2->stats , sizeof (ob1->stats) ) || ob1->attacktype != ob2->attacktype || ob1->magic != ob2->magic || ob1->slaying != ob2->slaying @@ -249,11 +243,21 @@ || ob1->move_on != ob2->move_on || ob1->move_off != ob2->move_off || ob1->move_slow != ob2->move_slow - || ob1->move_slow_penalty != ob2->move_slow_penalty) + || ob1->move_slow_penalty != ob2->move_slow_penalty + || memcmp (&ob1->resist, &ob2->resist, sizeof (ob1->resist)) + || memcmp (&ob1->stats , &ob2->stats , sizeof (ob1->stats))) + return 0; + + if ((ob1->flag ^ ob2->flag) + .reset (FLAG_INV_LOCKED) + .reset (FLAG_CLIENT_SENT) + .reset (FLAG_REMOVED) + .any ()) return 0; - /* This is really a spellbook check - really, we should - * check all objects in the inventory. + /* This is really a spellbook check - we should in general + * not merge objects with real inventories, as splitting them + * is hard. */ if (ob1->inv || ob2->inv) { @@ -264,7 +268,7 @@ return 0; /* more than one object in inv */ if (!object::can_merge (ob1->inv, ob2->inv)) - return 0; /* inventory objexts differ */ + return 0; /* inventory objects differ */ /* inventory ok - still need to check rest of this object to see * if it is valid. @@ -293,13 +297,13 @@ break; } - if (ob1->key_values != NULL || ob2->key_values != NULL) + if (ob1->key_values || ob2->key_values) { /* At least one of these has key_values. */ - if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) - /* One has fields, but the other one doesn't. */ - return 0; - else if (!compare_ob_value_lists (ob1, ob2)) + if ((!ob1->key_values) != (!ob2->key_values)) + return 0; /* One has fields, but the other one doesn't. */ + + if (!compare_ob_value_lists (ob1, ob2)) return 0; } @@ -315,9 +319,11 @@ if (k1 != k2) return 0; - else if (k1 == 0) + + if (k1 == 0) return 1; - else if (!cfperl_can_merge (ob1, ob2)) + + if (!cfperl_can_merge (ob1, ob2)) return 0; } } @@ -326,50 +332,106 @@ return 1; } +// find player who can see this object +object * +object::visible_to () const +{ + if (!flag [FLAG_REMOVED]) + { + // see if we are in a container of sorts + if (env) + { + // the player inventory itself is always visible + if (env->type == PLAYER) + return env; + + // else a player could have our env open + object *envest = env->outer_env (); + + // the player itself is always on a map, so we will find him here + // even if our inv is in a player. + if (envest->is_on_map ()) + if (object *pl = envest->ms ().player ()) + if (pl->container == env) + return pl; + } + else + { + // maybe there is a player standing on the same mapspace + // this will catch the case where "this" is a player + if (object *pl = ms ().player ()) + return pl; + } + } + + return 0; +} + +// adjust weight per container type ("of holding") +static sint32 +weight_adjust (object *op, sint32 weight) +{ + return op->type == CONTAINER + ? lerp (weight, 0, 100, 0, 100 - op->stats.Str) + : weight; +} + /* - * sum_weight() is a recursive function which calculates the weight - * an object is carrying. It goes through in figures out how much - * containers are carrying, and sums it up. + * adjust_weight(object, weight) adds the specified weight to an object, + * and also updates how much the environment(s) is/are carrying. */ -long -sum_weight (object *op) +static void +adjust_weight (object *op, sint32 weight) { - long sum; - object *inv; - - for (sum = 0, inv = op->inv; inv; inv = inv->below) + while (op) { - if (inv->inv) - sum_weight (inv); + weight = weight_adjust (op, weight); - sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1); - } + if (!weight) + return; - if (op->type == CONTAINER && op->stats.Str) - sum = (sum * (100 - op->stats.Str)) / 100; + op->carrying += weight; - if (op->carrying != sum) - op->carrying = sum; + if (object *pl = op->visible_to ()) + if (pl != op) // player is handled lazily + esrv_update_item (UPD_WEIGHT, pl, op); - return sum; + op = op->env; + } } -/** - * Return the outermost environment object for a given object. +/* + * this is a recursive function which calculates the weight + * an object is carrying. It goes through op and figures out how much + * containers are carrying, and sums it up. */ - -object * -object_get_env_recursive (object *op) +void +object::update_weight () { - while (op->env != NULL) - op = op->env; - return op; + sint32 sum = 0; + + for (object *op = inv; op; op = op->below) + { + if (op->inv) + op->update_weight (); + + sum += op->total_weight (); + } + + sum = weight_adjust (this, sum); + + if (sum != carrying) + { + carrying = sum; + + if (object *pl = visible_to ()) + if (pl != this) // player is handled lazily + esrv_update_item (UPD_WEIGHT, pl, this); + } } /* - * Used by: Crossedit: dump. Server DM commands: dumpbelow, dump. - * Some error messages. - * The result of the dump is stored in the static global errmsg array. + * Used by: Server DM commands: dumpbelow, dump. Some error messages. */ char * dump_object (object *op) @@ -393,16 +455,21 @@ object *tmp, *closest; int last_dist, i; - if (op->more == NULL) + if (!op->more) return op; - for (last_dist = distance (op, pl), closest = op, tmp = op->more; tmp != NULL; tmp = tmp->more) + + for (last_dist = distance (op, pl), closest = op, tmp = op->more; + tmp; + tmp = tmp->more) if ((i = distance (tmp, pl)) < last_dist) closest = tmp, last_dist = i; + return closest; } /* * Returns the object which has the count-variable equal to the argument. + * VERRRY slow. */ object * find_object (tag_t i) @@ -852,7 +919,7 @@ // need to check first, because the checks below might segfault // as we might be on an invalid mapspace and crossfire code // is too buggy to ensure that the inventory is empty. - // corollary: if you create arrows etc. with stuff in tis inventory, + // corollary: if you create arrows etc. with stuff in its inventory, // cf will crash below with off-map x and y if (!inv) return; @@ -863,13 +930,13 @@ */ if (!drop_to_ground || !map - || map->in_memory != MAP_IN_MEMORY + || map->in_memory != MAP_ACTIVE || map->nodrop || ms ().move_block == MOVE_ALL) { while (inv) { - inv->destroy_inv (drop_to_ground); + inv->destroy_inv (false); inv->destroy (); } } @@ -885,7 +952,7 @@ || op->type == TRAP || op->flag [FLAG_IS_A_TEMPLATE] || op->flag [FLAG_DESTROY_ON_DEATH]) - op->destroy (); + op->destroy (true); else map->insert (op, x, y); } @@ -902,18 +969,15 @@ void object::do_destroy () { - attachable::do_destroy (); - if (flag [FLAG_IS_LINKED]) remove_button_link (this); if (flag [FLAG_FRIENDLY]) remove_friendly_object (this); - if (!flag [FLAG_REMOVED]) - remove (); + remove (); - destroy_inv (true); + attachable::do_destroy (); deactivate (); unlink (); @@ -935,7 +999,7 @@ freed_map->nodrop = 1; freed_map->alloc (); - freed_map->in_memory = MAP_IN_MEMORY; + freed_map->in_memory = MAP_ACTIVE; } map = freed_map; @@ -964,8 +1028,7 @@ if (destroyed ()) return; - if (destroy_inventory) - destroy_inv (false); + destroy_inv (!destroy_inventory); if (is_head ()) if (sound_destroy) @@ -976,23 +1039,6 @@ attachable::destroy (); } -/* - * sub_weight() recursively (outwards) subtracts a number from the - * weight of an object (and what is carried by it's environment(s)). - */ -void -sub_weight (object *op, signed long weight) -{ - while (op != NULL) - { - if (op->type == CONTAINER) - weight = (signed long) (weight * (100 - op->stats.Str) / 100); - - op->carrying -= weight; - op = op->env; - } -} - /* op->remove (): * This function removes the object op from the linked list of objects * which it is currently tied to. When this function is done, the @@ -1006,12 +1052,16 @@ object *tmp, *last = 0; object *otmp; - if (QUERY_FLAG (this, FLAG_REMOVED)) + if (flag [FLAG_REMOVED]) return; - SET_FLAG (this, FLAG_REMOVED); INVOKE_OBJECT (REMOVE, this); + if (object *pl = visible_to ()) + esrv_del_item (pl->contr, count); + + flag [FLAG_REMOVED] = true; + if (more) more->remove (); @@ -1021,22 +1071,9 @@ */ if (env) { - if (nrof) - sub_weight (env, weight * nrof); - else - sub_weight (env, weight + carrying); + adjust_weight (env, -total_weight ()); - /* NO_FIX_PLAYER is set when a great many changes are being - * made to players inventory. If set, avoiding the call - * to save cpu time. - */ - if ((otmp = in_player ()) && otmp->contr && !QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) - otmp->update_stats (); - - if (above) - above->below = below; - else - env->inv = below; + *(above ? &above->below : &env->inv) = below; if (below) below->above = above; @@ -1045,10 +1082,19 @@ * the map, but we don't actually do that - it is up * to the caller to decide what we want to do. */ - x = env->x, y = env->y; - map = env->map; - above = 0, below = 0; - env = 0; + map = env->map; + x = env->x; + y = env->y; + above = 0; + below = 0; + env = 0; + + /* NO_FIX_PLAYER is set when a great many changes are being + * made to players inventory. If set, avoiding the call + * to save cpu time. + */ + if ((otmp = in_player ()) && otmp->contr && !QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) + otmp->update_stats (); } else if (map) { @@ -1105,7 +1151,8 @@ */ pl->close_container (); - pl->contr->ns->floorbox_update (); + //TODO: the floorbox prev/next might need updating + esrv_del_item (pl->contr, count); } for (tmp = ms.bot; tmp; tmp = tmp->above) @@ -1159,20 +1206,20 @@ ; for (; top; top = top->below) - { - if (top == op) - continue; + if (object::can_merge (op, top)) + { + top->nrof += op->nrof; - if (object::can_merge (op, top)) - { - top->nrof += op->nrof; + if (object *pl = top->visible_to ()) + esrv_update_item (UPD_NROF, pl, top); -/* CLEAR_FLAG(top,FLAG_STARTEQUIP);*/ - op->weight = 0; /* Don't want any adjustements now */ - op->destroy (); - return top; - } - } + op->weight = 0; // cancel the addition above + op->carrying = 0; // must be 0 already + + op->destroy (1); + + return top; + } return 0; } @@ -1241,8 +1288,6 @@ { assert (!op->flag [FLAG_FREED]); - object *top, *floor = NULL; - op->remove (); /* Ideally, the caller figures this out. However, it complicates a lot @@ -1251,7 +1296,7 @@ */ if (!xy_normalise (m, op->x, op->y)) { - op->destroy (); + op->destroy (1); return 0; } @@ -1270,8 +1315,11 @@ for (object *tmp = ms.bot; tmp; tmp = tmp->above) if (object::can_merge (op, tmp)) { + // TODO: we atcually want to update tmp, not op, + // but some caller surely breaks when we return tmp + // from here :/ op->nrof += tmp->nrof; - tmp->destroy (); + tmp->destroy (1); } CLEAR_FLAG (op, FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */ @@ -1301,6 +1349,8 @@ } else { + object *top, *floor = NULL; + top = ms.bot; /* If there are other objects, then */ @@ -1409,7 +1459,8 @@ op->map->dirty = true; if (object *pl = ms.player ()) - pl->contr->ns->floorbox_update (); + //TODO: the floorbox prev/next might need updating + esrv_send_item (pl, op); /* If this object glows, it may affect lighting conditions that are * visible to others on this map. But update_all_los is really @@ -1461,168 +1512,87 @@ void replace_insert_ob_in_map (const char *arch_string, object *op) { - object *tmp, *tmp1; - /* first search for itself and remove any old instances */ - for (tmp = op->ms ().bot; tmp; tmp = tmp->above) + for (object *tmp = op->ms ().bot; tmp; tmp = tmp->above) if (!strcmp (tmp->arch->archname, arch_string)) /* same archetype */ - tmp->destroy (); + tmp->destroy (1); - tmp1 = arch_to_object (archetype::find (arch_string)); + object *tmp = arch_to_object (archetype::find (arch_string)); - tmp1->x = op->x; - tmp1->y = op->y; - insert_ob_in_map (tmp1, op->map, op, 0); -} + tmp->x = op->x; + tmp->y = op->y; -object * -object::insert_at (object *where, object *originator, int flags) -{ - return where->map->insert (this, where->x, where->y, originator, flags); + insert_ob_in_map (tmp, op->map, op, 0); } -/* - * get_split_ob(ob,nr) splits up ob into two parts. The part which - * is returned contains nr objects, and the remaining parts contains - * the rest (or is removed and freed if that number is 0). - * On failure, NULL is returned, and the reason put into the - * global static errmsg array. - */ object * -get_split_ob (object *orig_ob, uint32 nr) +object::insert_at (object *where, object *originator, int flags) { - object *newob; - int is_removed = (QUERY_FLAG (orig_ob, FLAG_REMOVED) != 0); - - if (orig_ob->nrof < nr) - { - sprintf (errmsg, "There are only %d %ss.", orig_ob->nrof ? orig_ob->nrof : 1, &orig_ob->name); - return NULL; - } - - newob = object_create_clone (orig_ob); - - if ((orig_ob->nrof -= nr) < 1) - orig_ob->destroy (1); - else if (!is_removed) - { - if (orig_ob->env != NULL) - sub_weight (orig_ob->env, orig_ob->weight * nr); - if (orig_ob->env == NULL && orig_ob->map->in_memory != MAP_IN_MEMORY) - { - strcpy (errmsg, "Tried to split object whose map is not in memory."); - LOG (llevDebug, "Error, Tried to split object whose map is not in memory.\n"); - return NULL; - } - } - - newob->nrof = nr; - - return newob; + if (where->env) + return where->env->insert (this); + else + return where->map->insert (this, where->x, where->y, originator, flags); } /* - * decrease_ob_nr(object, number) decreases a specified number from - * the amount of an object. If the amount reaches 0, the object + * decrease(object, number) decreases a specified number from + * the amount of an object. If the amount reaches 0, the object * is subsequently removed and freed. * * Return value: 'op' if something is left, NULL if the amount reached 0 */ -object * -decrease_ob_nr (object *op, uint32 i) +bool +object::decrease (sint32 nr) { - object *tmp; + if (!nr) + return true; - if (i == 0) /* objects with op->nrof require this check */ - return op; + nr = min (nr, nrof); - if (i > op->nrof) - i = op->nrof; + nrof -= nr; - if (QUERY_FLAG (op, FLAG_REMOVED)) - op->nrof -= i; - else if (op->env) + if (nrof) { - /* is this object in the players inventory, or sub container - * therein? - */ - tmp = op->in_player (); - /* nope. Is this a container the player has opened? - * If so, set tmp to that player. - * IMO, searching through all the players will mostly - * likely be quicker than following op->env to the map, - * and then searching the map for a player. - */ - if (!tmp) - for_all_players (pl) - if (pl->ob->container == op->env) - { - tmp = pl->ob; - break; - } + adjust_weight (env, -weight * nr); // carrying == 0 - if (i < op->nrof) - { - sub_weight (op->env, op->weight * i); - op->nrof -= i; - if (tmp) - esrv_send_item (tmp, op); - } - else - { - op->remove (); - op->nrof = 0; - if (tmp) - esrv_del_item (tmp->contr, op->count); - } - } - else - { - object *above = op->above; + if (object *pl = visible_to ()) + esrv_update_item (UPD_NROF, pl, this); - if (i < op->nrof) - op->nrof -= i; - else - { - op->remove (); - op->nrof = 0; - } - - /* Since we just removed op, op->above is null */ - for (tmp = above; tmp; tmp = tmp->above) - if (tmp->type == PLAYER) - { - if (op->nrof) - esrv_send_item (tmp, op); - else - esrv_del_item (tmp->contr, op->count); - } + return true; } - - if (op->nrof) - return op; else { - op->destroy (); - return 0; + destroy (1); + return false; } } /* - * add_weight(object, weight) adds the specified weight to an object, - * and also updates how much the environment(s) is/are carrying. + * split(ob,nr) splits up ob into two parts. The part which + * is returned contains nr objects, and the remaining parts contains + * the rest (or is removed and returned if that number is 0). + * On failure, NULL is returned. */ -void -add_weight (object *op, signed long weight) +object * +object::split (sint32 nr) { - while (op != NULL) + int have = number_of (); + + if (have < nr) + return 0; + else if (have == nr) + { + remove (); + return this; + } + else { - if (op->type == CONTAINER) - weight = (signed long) (weight * (100 - op->stats.Str) / 100); + decrease (nr); - op->carrying += weight; - op = op->env; + object *op = object_create_clone (this); + op->nrof = nr; + return op; } } @@ -1657,81 +1627,63 @@ object * object::insert (object *op) { - if (!QUERY_FLAG (op, FLAG_REMOVED)) - op->remove (); - if (op->more) { LOG (llevError, "Tried to insert multipart object %s (%d)\n", &op->name, op->count); return op; } - CLEAR_FLAG (op, FLAG_OBJ_ORIGINAL); - CLEAR_FLAG (op, FLAG_REMOVED); + op->remove (); + + op->flag [FLAG_OBJ_ORIGINAL] = 0; if (op->nrof) - { - for (object *tmp = inv; tmp; tmp = tmp->below) - if (object::can_merge (tmp, op)) - { - /* return the original object and remove inserted object - (client needs the original object) */ - tmp->nrof += op->nrof; - /* Weight handling gets pretty funky. Since we are adding to - * tmp->nrof, we need to increase the weight. - */ - add_weight (this, op->weight * op->nrof); - SET_FLAG (op, FLAG_REMOVED); - op->destroy (); /* free the inserted object */ - op = tmp; - op->remove (); /* and fix old object's links */ - CLEAR_FLAG (op, FLAG_REMOVED); - break; - } + for (object *tmp = inv; tmp; tmp = tmp->below) + if (object::can_merge (tmp, op)) + { + /* return the original object and remove inserted object + (client needs the original object) */ + tmp->nrof += op->nrof; - /* I assume combined objects have no inventory - * We add the weight - this object could have just been removed - * (if it was possible to merge). calling remove_ob will subtract - * the weight, so we need to add it in again, since we actually do - * the linking below - */ - add_weight (this, op->weight * op->nrof); - } - else - add_weight (this, (op->weight + op->carrying)); + if (object *pl = tmp->visible_to ()) + esrv_update_item (UPD_NROF, pl, tmp); - if (object *otmp = this->in_player ()) - if (otmp->contr && !QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) - otmp->update_stats (); + adjust_weight (this, op->total_weight ()); - op->owner = 0; // its his/hers now. period. + op->destroy (1); + op = tmp; + goto inserted; + } + + op->owner = 0; // it's his/hers now. period. op->map = 0; - op->env = this; + op->x = 0; + op->y = 0; + op->above = 0; - op->below = 0; - op->x = op->y = 0; + op->below = inv; + op->env = this; + + if (inv) + inv->above = op; + inv = op; + + op->flag [FLAG_REMOVED] = 0; + + if (object *pl = op->visible_to ()) + esrv_send_item (pl, op); + + adjust_weight (this, op->total_weight ()); + +inserted: /* reset the light list and los of the players on the map */ - if (op->glow_radius && map) - { -#ifdef DEBUG_LIGHTS - LOG (llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n", op->name); -#endif /* DEBUG_LIGHTS */ - if (map->darkness) - update_all_los (map, x, y); - } + if (op->glow_radius && map && map->darkness) + update_all_los (map, x, y); - /* Client has no idea of ordering so lets not bother ordering it here. - * It sure simplifies this function... - */ - if (!inv) - inv = op; - else - { - op->below = inv; - op->below->above = op; - inv = op; - } + // if this is a player's inventory, update stats + if (type == PLAYER && !flag [FLAG_NO_FIX_PLAYER]) + update_stats (); INVOKE_OBJECT (INSERT, this); @@ -2619,7 +2571,7 @@ title ? (const char *)title : "", flag_desc (flagdesc, 512), type); - if (!this->flag[FLAG_REMOVED] && env) + if (!flag[FLAG_REMOVED] && env) p += snprintf (p, 256, "(in %s)", env->debug_desc (info2)); if (map) @@ -2671,7 +2623,7 @@ closer->destroy (); #endif - old_container->flag [FLAG_APPLIED] = 0; + old_container->flag [FLAG_APPLIED] = false; container = 0; esrv_update_item (UPD_FLAGS, this, old_container); @@ -2697,7 +2649,7 @@ new_draw_info_format (NDI_UNIQUE, 0, this, "You open %s.", query_name (new_container)); - new_container->flag [FLAG_APPLIED] = 1; + new_container->flag [FLAG_APPLIED] = true; container = new_container; esrv_update_item (UPD_FLAGS, this, new_container); @@ -2739,7 +2691,7 @@ } void -object::play_sound (faceidx sound) const +object::play_sound (faceidx sound) { if (!sound) return;