--- deliantra/server/common/object.C 2008/04/22 23:50:23 1.216 +++ deliantra/server/common/object.C 2008/05/03 08:50:30 1.226 @@ -336,7 +336,7 @@ object * object::visible_to () const { - if (!flag [FLAG_REMOVED]) + if (client_visible () && !flag [FLAG_REMOVED]) { // see if we are in a container of sorts if (env) @@ -360,7 +360,8 @@ // 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; + if (!pl->container || this == pl->container) + return pl; } } @@ -607,13 +608,11 @@ object & object::operator =(const object &src) { - bool is_freed = flag [FLAG_FREED]; - bool is_removed = flag [FLAG_REMOVED]; + remove (); *(object_copy *)this = src; - flag [FLAG_FREED] = is_freed; - flag [FLAG_REMOVED] = is_removed; + flag [FLAG_REMOVED] = true; /* Copy over key_values, if any. */ if (src.key_values) @@ -687,6 +686,7 @@ { object *neu = create (); copy_to (neu); + neu->map = map; // not copied by copy_to return neu; } @@ -747,14 +747,14 @@ void update_object (object *op, int action) { - if (op == NULL) + if (!op) { /* this should never happen */ - LOG (llevDebug, "update_object() called for NULL object.\n"); + LOG (llevError | logBacktrace, "update_object() called for NULL object.\n"); return; } - if (op->env) + if (!op->is_on_map ()) { /* Animation is currently handled by client, so nothing * to do in this case. @@ -762,12 +762,6 @@ return; } - /* If the map is saving, don't do anything as everything is - * going to get freed anyways. - */ - if (!op->map || op->map->in_memory == MAP_SAVING) - return; - /* make sure the object is within map boundaries */ if (op->x < 0 || op->x >= op->map->width || op->y < 0 || op->y >= op->map->height) { @@ -919,7 +913,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; @@ -936,7 +930,7 @@ { while (inv) { - inv->destroy_inv (drop_to_ground); + inv->destroy_inv (false); inv->destroy (); } } @@ -952,7 +946,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); } @@ -966,6 +960,21 @@ return op; } +static struct freed_map : maptile +{ + freed_map () + { + path = ""; + name = "/internal/freed_objects_map"; + width = 3; + height = 3; + nodrop = 1; + + alloc (); + in_memory = MAP_ACTIVE; + } +} freed_map; // freed objects are moved here to avoid crashes + void object::do_destroy () { @@ -979,35 +988,15 @@ attachable::do_destroy (); - destroy_inv (true); - deactivate (); unlink (); flag [FLAG_FREED] = 1; // hack to ensure that freed objects still have a valid map - { - static maptile *freed_map; // freed objects are moved here to avoid crashes - - if (!freed_map) - { - freed_map = new maptile; - - freed_map->path = ""; - freed_map->name = "/internal/freed_objects_map"; - freed_map->width = 3; - freed_map->height = 3; - freed_map->nodrop = 1; - - freed_map->alloc (); - freed_map->in_memory = MAP_ACTIVE; - } - - map = freed_map; - x = 1; - y = 1; - } + map = &freed_map; + x = 1; + y = 1; if (more) { @@ -1030,8 +1019,14 @@ if (destroyed ()) return; - if (destroy_inventory) - destroy_inv (false); + if (!is_head () && !head->destroyed ()) + { + LOG (llevError | logBacktrace, "tried to destroy the tail of an object"); + head->destroy (destroy_inventory); + return; + } + + destroy_inv (!destroy_inventory); if (is_head ()) if (sound_destroy) @@ -1060,9 +1055,6 @@ INVOKE_OBJECT (REMOVE, this); - if (object *pl = visible_to ()) - esrv_del_item (pl->contr, count); - flag [FLAG_REMOVED] = true; if (more) @@ -1074,6 +1066,11 @@ */ if (env) { + flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed + if (object *pl = visible_to ()) + esrv_del_item (pl->contr, count); + flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed + adjust_weight (env, -total_weight ()); *(above ? &above->below : &env->inv) = below; @@ -1101,20 +1098,30 @@ } else if (map) { - if (type == PLAYER) + map->dirty = true; + mapspace &ms = this->ms (); + + if (object *pl = ms.player ()) { - // leaving a spot always closes any open container on the ground - if (container && !container->env) - // this causes spurious floorbox updates, but it ensures - // that the CLOSE event is being sent. - close_container (); + if (type == PLAYER) // this == pl(!) + { + // leaving a spot always closes any open container on the ground + if (container && !container->env) + // this causes spurious floorbox updates, but it ensures + // that the CLOSE event is being sent. + close_container (); - --map->players; - map->touch (); - } + --map->players; + map->touch (); + } + else if (pl->container == this) + { + // removing a container should close it + close_container (); + } - map->dirty = true; - mapspace &ms = this->ms (); + esrv_del_item (pl->contr, count); + } /* link the object above us */ if (above) @@ -1154,7 +1161,11 @@ */ pl->close_container (); - pl->contr->ns->floorbox_update (); + //TODO: the floorbox prev/next might need updating + //esrv_del_item (pl->contr, count); + //TODO: update floorbox to preserve ordering + if (pl->contr->ns) + pl->contr->ns->floorbox_update (); } for (tmp = ms.bot; tmp; tmp = tmp->above) @@ -1290,8 +1301,6 @@ { assert (!op->flag [FLAG_FREED]); - object *top, *floor = NULL; - op->remove (); /* Ideally, the caller figures this out. However, it complicates a lot @@ -1300,7 +1309,7 @@ */ if (!xy_normalise (m, op->x, op->y)) { - op->destroy (); + op->destroy (1); return 0; } @@ -1319,6 +1328,9 @@ 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 (1); } @@ -1350,6 +1362,8 @@ } else { + object *top, *floor = NULL; + top = ms.bot; /* If there are other objects, then */ @@ -1458,7 +1472,11 @@ 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); + //TODO: update floorbox to preserve ordering + if (pl->contr->ns) + pl->contr->ns->floorbox_update (); /* If this object glows, it may affect lighting conditions that are * visible to others on this map. But update_all_los is really @@ -2315,17 +2333,18 @@ object * object_create_clone (object *asrc) { - object *dst = 0, *tmp, *src, *prev, *item; + object *dst = 0; if (!asrc) return 0; - src = asrc->head_ (); + object *src = asrc->head_ (); - prev = 0; + object *prev = 0; for (object *part = src; part; part = part->more) { - tmp = part->clone (); + object *tmp = part->clone (); + tmp->x -= src->x; tmp->y -= src->y; @@ -2345,7 +2364,7 @@ prev = tmp; } - for (item = src->inv; item; item = item->below) + for (object *item = src->inv; item; item = item->below) insert_ob_in_ob (object_create_clone (item), dst); return dst; @@ -2569,7 +2588,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) @@ -2609,7 +2628,9 @@ if (container == new_container) return; - if (object *old_container = container) + object *old_container = container; + + if (old_container) { if (INVOKE_OBJECT (CLOSE, old_container, ARG_OBJECT (this))) return; @@ -2621,10 +2642,15 @@ closer->destroy (); #endif + // make sure the container is available + esrv_send_item (this, old_container); + old_container->flag [FLAG_APPLIED] = false; container = 0; + // client needs item update to make it work, client bug requires this to be separate esrv_update_item (UPD_FLAGS, this, old_container); + new_draw_info_format (NDI_UNIQUE, 0, this, "You close %s.", query_name (old_container)); play_sound (sound_find ("chest_close")); } @@ -2647,13 +2673,19 @@ new_draw_info_format (NDI_UNIQUE, 0, this, "You open %s.", query_name (new_container)); + // make sure the container is available, client bug requires this to be separate + esrv_send_item (this, new_container); + new_container->flag [FLAG_APPLIED] = true; container = new_container; + // client needs flag change esrv_update_item (UPD_FLAGS, this, new_container); esrv_send_inventory (this, new_container); play_sound (sound_find ("chest_open")); } +// else if (!old_container->env && contr && contr->ns) +// contr->ns->floorbox_reset (); } object *