--- deliantra/server/common/object.C 2007/08/08 04:52:59 1.174 +++ deliantra/server/common/object.C 2007/10/15 17:50:27 1.193 @@ -256,13 +256,14 @@ */ if (ob1->inv || ob2->inv) { - /* if one object has inventory but the other doesn't, not equiv */ - if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv)) - return 0; + if (!(ob1->inv && ob2->inv)) + return 0; /* inventories differ in length */ + + if (ob1->inv->below || ob2->inv->below) + return 0; /* more than one object in inv */ - /* Now check to see if the two inventory objects could merge */ if (!object::can_merge (ob1->inv, ob2->inv)) - return 0; + return 0; /* inventory objexts differ */ /* inventory ok - still need to check rest of this object to see * if it is valid. @@ -307,8 +308,17 @@ ob2->optimise (); if (ob1->self || ob2->self) - if (!cfperl_can_merge (ob1, ob2)) - return 0; + { + int k1 = ob1->self ? HvTOTALKEYS (SvRV (ob1->self)) : 0; + int k2 = ob2->self ? HvTOTALKEYS (SvRV (ob2->self)) : 0; + + if (k1 != k2) + return 0; + else if (k1 == 0) + return 1; + else if (!cfperl_can_merge (ob1, ob2)) + return 0; + } } /* Everything passes, must be OK. */ @@ -376,7 +386,6 @@ * multi-object 1 which is closest to the second object. * If it's not a multi-object, it is returned. */ - object * get_nearest_part (object *op, const object *pl) { @@ -431,22 +440,15 @@ /* * Sets the owner and sets the skill and exp pointers to owner's current * skill and experience objects. + * ACTUALLY NO! investigate! TODO */ void object::set_owner (object *owner) { - if (!owner) - return; - - /* next line added to allow objects which own objects */ - /* Add a check for ownercounts in here, as I got into an endless loop - * with the fireball owning a poison cloud which then owned the - * fireball. I believe that was caused by one of the objects getting - * freed and then another object replacing it. Since the ownercounts - * didn't match, this check is valid and I believe that cause is valid. - */ - while (owner->owner) - owner = owner->owner; + // allow objects which own objects + if (owner) + while (owner->owner) + owner = owner->owner; this->owner = owner; } @@ -588,7 +590,7 @@ *dst = *this; if (speed < 0) - dst->speed_left = speed_left - rndm (); + dst->speed_left -= rndm (); dst->set_speed (dst->speed); } @@ -925,6 +927,7 @@ { freed_map = new maptile; + freed_map->path = ""; freed_map->name = "/internal/freed_objects_map"; freed_map->width = 3; freed_map->height = 3; @@ -1091,18 +1094,23 @@ int check_walk_off = !flag [FLAG_NO_APPLY]; - for (tmp = ms.bot; tmp; tmp = tmp->above) + if (object *pl = ms.player ()) { - /* No point updating the players look faces if he is the object - * being removed. - */ - - if (tmp->type == PLAYER && tmp->container == this) + if (pl->container == this) /* If a container that the player is currently using somehow gets * removed (most likely destroyed), update the player view * appropriately. */ - tmp->close_container (); + pl->close_container (); + + pl->contr->ns->floorbox_update (); + } + + for (tmp = ms.bot; tmp; tmp = tmp->above) + { + /* No point updating the players look faces if he is the object + * being removed. + */ /* See if object moving off should effect something */ if (check_walk_off @@ -1235,25 +1243,14 @@ op->remove (); -#if 0 - if (!m->active != !op->active) - if (m->active) - op->activate_recursive (); - else - op->deactivate_recursive (); -#endif - - if (out_of_map (m, op->x, op->y)) + /* Ideally, the caller figures this out. However, it complicates a lot + * of areas of callers (eg, anything that uses find_free_spot would now + * need extra work + */ + if (!xy_normalise (m, op->x, op->y)) { - LOG (llevError, "Trying to insert object outside the map.\n%s\n", op->debug_desc ()); -#ifdef MANY_CORES - /* Better to catch this here, as otherwise the next use of this object - * is likely to cause a crash. Better to find out where it is getting - * improperly inserted. - */ - abort (); -#endif - return op; + op->destroy (); + return 0; } if (object *more = op->more) @@ -1262,13 +1259,6 @@ CLEAR_FLAG (op, FLAG_REMOVED); - /* Ideally, the caller figures this out. However, it complicates a lot - * of areas of callers (eg, anything that uses find_free_spot would now - * need extra work - */ - if (!xy_normalise (m, op->x, op->y)) - return 0; - op->map = m; mapspace &ms = op->ms (); @@ -1312,7 +1302,7 @@ top = ms.bot; /* If there are other objects, then */ - if ((!(flag & INS_MAP_LOAD)) && top) + if (top) { object *last = 0; @@ -1374,8 +1364,6 @@ top = last->below; } } /* If objects on this space */ - if (flag & INS_MAP_LOAD) - top = ms.top; if (flag & INS_ABOVE_FLOOR_ONLY) top = floor; @@ -1418,13 +1406,8 @@ op->map->dirty = true; - /* If we have a floor, we know the player, if any, will be above - * it, so save a few ticks and start from there. - */ - if (!(flag & INS_MAP_LOAD)) - if (object *pl = ms.player ()) - if (pl->contr->ns) - pl->contr->ns->floorbox_update (); + if (object *pl = ms.player ()) + 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 @@ -1672,8 +1655,6 @@ object * object::insert (object *op) { - object *tmp, *otmp; - if (!QUERY_FLAG (op, FLAG_REMOVED)) op->remove (); @@ -1685,9 +1666,10 @@ CLEAR_FLAG (op, FLAG_OBJ_ORIGINAL); CLEAR_FLAG (op, FLAG_REMOVED); + if (op->nrof) { - for (tmp = inv; tmp != NULL; tmp = tmp->below) + for (object *tmp = inv; tmp; tmp = tmp->below) if (object::can_merge (tmp, op)) { /* return the original object and remove inserted object @@ -1716,19 +1698,19 @@ else add_weight (this, (op->weight + op->carrying)); - otmp = this->in_player (); - if (otmp && otmp->contr) - if (!QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) + if (object *otmp = this->in_player ()) + if (otmp->contr && !QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) otmp->update_stats (); - op->map = 0; - op->env = this; + op->owner = 0; // its his/hers now. period. + op->map = 0; + op->env = this; op->above = 0; op->below = 0; - op->x = 0, op->y = 0; + op->x = op->y = 0; /* reset the light list and los of the players on the map */ - if ((op->glow_radius != 0) && 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); @@ -2018,14 +2000,30 @@ int find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop) { - int index = 0, flag; int altern[SIZEOFFREE]; + int index = 0, flag; for (int i = start; i < stop; i++) { - flag = ob_blocked (ob, m, x + freearr_x[i], y + freearr_y[i]); - if (!flag) - altern [index++] = i; + mapxy pos (m, x, y); pos.move (i); + + if (!pos.normalise ()) + continue; + + mapspace &ms = *pos; + + if (ms.flags () & P_IS_ALIVE) + continue; + + /* However, often + * ob doesn't have any move type (when used to place exits) + * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work. + */ + if (ob->move_type == 0 && ms.move_block != MOVE_ALL) + { + altern [index++] = i; + continue; + } /* Basically, if we find a wall on a space, we cut down the search size. * In this way, we won't return spaces that are on another side of a wall. @@ -2035,8 +2033,19 @@ * to only the spaces immediately surrounding the target area, and * won't look 2 spaces south of the target space. */ - else if ((flag & P_NO_PASS) && maxfree[i] < stop) - stop = maxfree[i]; + if (ms.move_block == MOVE_ALL && maxfree[i] < stop) + { + stop = maxfree[i]; + continue; + } + + /* Note it is intentional that we check ob - the movement type of the + * head of the object should correspond for the entire object. + */ + if (OB_TYPE_MOVE_BLOCK (ob, ms.move_block)) + continue; + + altern [index++] = i; } if (!index) @@ -2055,7 +2064,7 @@ find_first_free_spot (const object *ob, maptile *m, int x, int y) { for (int i = 0; i < SIZEOFFREE; i++) - if (!ob_blocked (ob, m, x + freearr_x[i], y + freearr_y[i])) + if (!ob->blocked (m, x + freearr_x[i], y + freearr_y[i])) return i; return -1; @@ -2342,7 +2351,6 @@ * * Add a check so we can't pick up invisible objects (0.93.8) */ - int can_pick (const object *who, const object *item) { @@ -2610,7 +2618,7 @@ title ? (const char *)title : "", flag_desc (flagdesc, 512), type); - if (env) + if (!this->flag[FLAG_REMOVED] && env) p += snprintf (p, 256, "(in %s)", env->debug_desc (info2)); if (map) @@ -2667,6 +2675,7 @@ 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")); } if (new_container) @@ -2692,6 +2701,7 @@ esrv_update_item (UPD_FLAGS, this, new_container); esrv_send_inventory (this, new_container); + play_sound (sound_find ("chest_open")); } } @@ -2727,3 +2737,21 @@ insert (force); } +void +object::play_sound (faceidx sound) const +{ + if (!sound) + return; + + if (flag [FLAG_REMOVED]) + return; + + if (env) + { + if (object *pl = in_player ()) + pl->contr->play_sound (sound); + } + else + map->play_sound (sound, x, y); +} +