--- deliantra/server/common/object.C 2008/07/16 14:29:40 1.250 +++ deliantra/server/common/object.C 2008/12/27 04:15:56 1.273 @@ -34,6 +34,7 @@ UUID UUID::cur; static uint64_t seq_next_save; static const uint64 UUID_GAP = 1<<19; +uint32_t mapspace::smellcount = 10000; objectvec objects; activevec actives; @@ -188,12 +189,9 @@ || ob1->name != ob2->name) return 0; - /* 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 || ob1->nrof + ob2->nrof > (1UL << 31)) + /* Do not merge objects if nrof would overflow, assume nrof + * is always 0 .. 2**31-1 */ + if (ob1->nrof > 0x7fffffff - ob2->nrof) return 0; /* If the objects have been identified, set the BEEN_APPLIED flag. @@ -237,7 +235,6 @@ if ((ob1->flag ^ ob2->flag) .reset (FLAG_INV_LOCKED) - .reset (FLAG_CLIENT_SENT) .reset (FLAG_REMOVED) .any ()) return 0; @@ -329,7 +326,7 @@ if (env) { // the player inventory itself is always visible - if (env->type == PLAYER) + if (env->is_player ()) return env; // else a player could have our env open @@ -642,7 +639,7 @@ if (speed < 0) dst->speed_left -= rndm (); - dst->set_speed (dst->speed); + dst->activate (); } void @@ -764,7 +761,7 @@ // this is likely overkill, TODO: revisit (schmorp) if ((QUERY_FLAG (op, FLAG_BLOCKSVIEW) && !(m.flags_ & P_BLOCKSVIEW)) || (QUERY_FLAG (op, FLAG_NO_MAGIC) && !(m.flags_ & P_NO_MAGIC)) - || (op->type == PLAYER && !(m.flags_ & P_PLAYER)) + || (op->is_player () && !(m.flags_ & P_PLAYER)) || (op->type == SAFE_GROUND && !(m.flags_ & P_SAFE)) || (QUERY_FLAG (op, FLAG_ALIVE) && !(m.flags_ & P_IS_ALIVE)) || (QUERY_FLAG (op, FLAG_DAMNED) && !(m.flags_ & P_NO_CLERIC)) @@ -772,18 +769,18 @@ || (m.move_off | op->move_off ) != m.move_off || (m.move_slow | op->move_slow) != m.move_slow /* This isn't perfect, but I don't expect a lot of objects to - * to have move_allow right now. + * have move_allow right now. */ || ((m.move_block | op->move_block) & ~op->move_allow) != m.move_block || 1) // the above is not strong enough a test to skip updating. los maybe? TODO (Schmorp) - m.flags_ = 0; + m.invalidate (); } /* if the object is being removed, we can't make intelligent * decisions, because remove_ob can't really pass the object * that is being removed. */ else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) - m.flags_ = 0; + m.invalidate (); else if (action == UP_OBJ_FACE) /* Nothing to do for that case */ ; else @@ -836,6 +833,9 @@ if (active) return; + if (has_active_speed () && flag [FLAG_FREED]) LOG (llevError | logBacktrace, "BUG: tried to activate freed object %s\n", debug_desc ());//D + if (has_active_speed () && flag [FLAG_DEBUG]) LOG (llevError | logBacktrace, "BUG: tried to activate DEBUG object %s\n", debug_desc ());//D temp + if (has_active_speed ()) actives.insert (this); } @@ -912,7 +912,7 @@ || ms ().move_block == MOVE_ALL) { while (inv) - inv->destroy (true); + inv->destroy (); } else { /* Put objects in inventory onto this space */ @@ -926,7 +926,7 @@ || op->type == TRAP || op->flag [FLAG_IS_A_TEMPLATE] || op->flag [FLAG_DESTROY_ON_DEATH]) - op->destroy (true); + op->destroy (); else map->insert (op, x, y); } @@ -1000,7 +1000,7 @@ } void -object::destroy (bool destroy_inventory) +object::destroy () { if (destroyed ()) return; @@ -1008,11 +1008,11 @@ if (!is_head () && !head->destroyed ()) { LOG (llevError | logBacktrace, "tried to destroy the tail of an object"); - head->destroy (destroy_inventory); + head->destroy (); return; } - destroy_inv (!destroy_inventory); + destroy_inv (false); if (is_head ()) if (sound_destroy) @@ -1059,6 +1059,8 @@ adjust_weight (env, -total_weight ()); + object *pl = in_player (); + /* we set up values so that it could be inserted into * the map, but we don't actually do that - it is up * to the caller to decide what we want to do. @@ -1079,8 +1081,14 @@ * 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 (pl) + if (pl->is_player () && (glow_radius || !QUERY_FLAG (pl, FLAG_NO_FIX_PLAYER))) + { + pl->update_stats (); + + if (glow_radius && pl->is_on_map ()) + update_all_los (pl->map, pl->x, pl->y); + } } else if (map) { @@ -1089,8 +1097,11 @@ if (object *pl = ms.player ()) { - if (type == PLAYER) // this == pl(!) + if (is_player ()) { + if (!flag [FLAG_WIZPASS]) + ms.smell = ++mapspace::smellcount; // remember the smell of the player + // leaving a spot always closes any open container on the ground if (container && !container->env) // this causes spurious floorbox updates, but it ensures @@ -1117,6 +1128,8 @@ above = 0; below = 0; + ms.invalidate (); + if (map->in_memory == MAP_SAVING) return; @@ -1158,14 +1171,7 @@ last = tmp; } - /* last == NULL if there are no objects on this space */ - //TODO: this makes little sense, why only update the topmost object? - if (!last) - map->at (x, y).flags_ = 0; - else - update_object (last, UP_OBJ_REMOVE); - - if (flag [FLAG_BLOCKSVIEW] || glow_radius) + if (affects_los ()) update_all_los (map, x, y); } } @@ -1199,7 +1205,7 @@ op->weight = 0; // cancel the addition above op->carrying = 0; // must be 0 already - op->destroy (1); + op->destroy (); return top; } @@ -1271,22 +1277,11 @@ object * insert_ob_in_map (object *op, maptile *m, object *originator, int flag) { - if (op->is_on_map ()) - { - LOG (llevError, "insert_ob_in_map called for object already on map"); - abort (); - } - - if (op->env) - { - LOG (llevError, "insert_ob_in_map called for object in an inventory (proceeding)"); - op->remove (); - } + op->remove (); - if (op->face && !face_info (op->face))//D TODO: remove soon + if (m == &freed_map)//D TODO: remove soon {//D - LOG (llevError | logBacktrace, "op->face out of bounds: %s", op->debug_desc ());//D - op->face = 1;//D + LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D }//D /* Ideally, the caller figures this out. However, it complicates a lot @@ -1295,7 +1290,7 @@ */ if (!xy_normalise (m, op->x, op->y)) { - op->head_ ()->destroy (1);// remove head_ once all tail object destroyers found + op->head_ ()->destroy ();// remove head_ once all tail object destroyers found return 0; } @@ -1318,7 +1313,7 @@ // but some caller surely breaks when we return tmp // from here :/ op->nrof += tmp->nrof; - tmp->destroy (1); + tmp->destroy (); } CLEAR_FLAG (op, FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */ @@ -1433,7 +1428,7 @@ } } - if (op->type == PLAYER) + if (op->is_player ()) { op->contr->do_los = 1; ++op->map->players; @@ -1458,8 +1453,11 @@ * or just updating the P_UPTODATE for spaces within this area * of effect may be sufficient. */ - if (op->map->darkness && (op->glow_radius != 0)) - update_all_los (op->map, op->x, op->y); + if (op->affects_los ()) + { + op->ms ().invalidate (); + update_all_los (op->map, op->x, op->y); + } /* updates flags (blocked, alive, no magic, etc) for this map space */ update_object (op, UP_OBJ_INSERT); @@ -1503,7 +1501,7 @@ for (object *tmp = op->ms ().bot; tmp; tmp = tmp->above) if (!strcmp (tmp->arch->archname, arch_string)) /* same archetype */ - tmp->destroy (1); + tmp->destroy (); object *tmp = arch_to_object (archetype::find (arch_string)); @@ -1537,10 +1535,9 @@ nr = min (nr, nrof); - nrof -= nr; - - if (nrof) + if (nrof > nr) { + nrof -= nr; adjust_weight (env, -weight * max (1, nr)); // carrying == 0 if (object *pl = visible_to ()) @@ -1637,7 +1634,7 @@ adjust_weight (this, op->total_weight ()); - op->destroy (1); + op->destroy (); op = tmp; goto inserted; } @@ -1665,11 +1662,13 @@ inserted: /* reset the light list and los of the players on the map */ - if (op->glow_radius && map && map->darkness) - update_all_los (map, x, y); - - // if this is a player's inventory, update stats - if (type == PLAYER && !flag [FLAG_NO_FIX_PLAYER]) + if (op->glow_radius && is_on_map ()) + { + update_stats (); + update_all_los (map, x, y); + } + else if (is_player () && !flag [FLAG_NO_FIX_PLAYER]) + // if this is a player's inventory, update stats update_stats (); INVOKE_OBJECT (INSERT, this); @@ -1763,7 +1762,7 @@ float diff = tmp->move_slow_penalty * fabs (op->speed); - if (op->type == PLAYER) + if (op->is_player ()) if ((QUERY_FLAG (tmp, FLAG_IS_HILLY) && find_skill_by_number (op, SK_CLIMBING)) || (QUERY_FLAG (tmp, FLAG_IS_WOODED) && find_skill_by_number (op, SK_WOODSMAN))) diff /= 4.0; @@ -1981,7 +1980,7 @@ if (OB_TYPE_MOVE_BLOCK (ob, ms.move_block)) continue; - if (ob->blocked (m, pos.x, pos.y)) + if (ob->blocked (pos.m, pos.x, pos.y)) continue; altern [index++] = i; @@ -2099,7 +2098,7 @@ else if (mflags & P_IS_ALIVE) { for (tmp = ms.bot; tmp; tmp = tmp->above) - if ((tmp->flag [FLAG_MONSTER] || tmp->type == PLAYER) + if ((tmp->flag [FLAG_MONSTER] || tmp->is_player ()) && (tmp != exclude || (tmp->head_ () != tmp && tmp->head_ () != exclude))) break; @@ -2295,7 +2294,7 @@ { return /*QUERY_FLAG(who,FLAG_WIZ)|| */ (item->weight > 0 && !QUERY_FLAG (item, FLAG_NO_PICK) && - !QUERY_FLAG (item, FLAG_ALIVE) && !item->invisible && (who->type == PLAYER || item->weight < who->weight / 3)); + !QUERY_FLAG (item, FLAG_ALIVE) && !item->invisible && (who->is_player () || item->weight < who->weight / 3)); } /* @@ -2558,7 +2557,7 @@ return 0; } -void +object * object::force_add (const shstr name, int duration) { if (object *force = force_find (name)) @@ -2574,7 +2573,7 @@ force->flag [FLAG_IS_USED_UP] = true; force->flag [FLAG_APPLIED] = true; - insert (force); + return insert (force); } void @@ -2595,3 +2594,36 @@ map->play_sound (sound, x, y); } +void +object::make_noise () +{ + // we do not model noise in the map, so instead put + // a temporary light into the noise source + // could use the map instead, but that's less reliable for our + // goal, which is to make invisibility a bit harder to exploit + + // currently only works sensibly for players + if (!is_player ()) + return; + + // find old force, or create new one + object *force = force_find (shstr_noise_force); + + if (force) + force->speed_left = -1.f; // patch old speed up + else + { + force = archetype::get (shstr_noise_force); + + force->slaying = shstr_noise_force; + force->stats.food = 1; + force->speed_left = -1.f; + + force->set_speed (1.f / 4.f); + force->flag [FLAG_IS_USED_UP] = true; + force->flag [FLAG_APPLIED] = true; + + insert (force); + } +} +