--- deliantra/server/common/object.C 2006/12/30 10:16:10 1.96 +++ deliantra/server/common/object.C 2007/01/07 23:12:03 1.110 @@ -1,6 +1,7 @@ /* CrossFire, A Multiplayer game for X-windows + Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team Copyright (C) 2001 Mark Wedel & Crossfire Development Team Copyright (C) 1992 Frank Tore Johansen @@ -38,7 +39,8 @@ static UUID uuid; const uint64 UUID_SKIP = 1<<19; -object *active_objects; /* List of active objects that need to be processed */ +objectvec objects; +activevec actives; short freearr_x[SIZEOFFREE] = { 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, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1 @@ -278,7 +280,7 @@ * be animated or have a very low speed. Is this an attempted monster * check? */ - if (!QUERY_FLAG (ob1, FLAG_ANIMATE) && FABS ((ob1)->speed) > MIN_ACTIVE_SPEED) + if (!QUERY_FLAG (ob1, FLAG_ANIMATE) && ob1->has_active_speed ()) return 0; switch (ob1->type) @@ -392,15 +394,12 @@ /* * Returns the object which has the count-variable equal to the argument. */ - object * find_object (tag_t i) { - for (object *op = object::first; op; op = op->next) - if (op->count == i) - return op; - - return 0; + return ((unsigned int)i) < objects.size () + ? objects [i] + : 0; } /* @@ -408,14 +407,13 @@ * Used only by the patch command, but not all that useful. * Enables features like "patch food 999" */ - object * find_object_name (const char *str) { shstr_cmp str_ (str); object *op; - for (op = object::first; op != NULL; op = op->next) + for_all_objects (op) if (op->name == str_) break; @@ -565,45 +563,10 @@ this->speed = speed; - if (FABS (speed) > MIN_ACTIVE_SPEED) - { - /* If already on active list, don't do anything */ - if (active_next || active_prev || this == active_objects) - return; - - /* process_events() expects us to insert the object at the beginning - * of the list. */ - active_next = active_objects; - - if (active_next) - active_next->active_prev = this; - - active_objects = this; - } + if (has_active_speed ()) + activate (); else - { - /* If not on the active list, nothing needs to be done */ - if (!active_next && !active_prev && this != active_objects) - return; - - if (!active_prev) - { - active_objects = active_next; - - if (active_next) - active_next->active_prev = 0; - } - else - { - active_prev->active_next = active_next; - - if (active_next) - active_next->active_prev = active_prev; - } - - active_next = 0; - active_prev = 0; - } + deactivate (); } /* @@ -661,7 +624,7 @@ mapspace &m = op->ms (); - if (m.flags_ & P_NEED_UPDATE) + if (!(m.flags_ & P_UPTODATE)) /* nop */; else if (action == UP_OBJ_INSERT) { @@ -680,14 +643,14 @@ */ || ((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_ = P_NEED_UPDATE; + m.flags_ = 0; } /* 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_ = P_NEED_UPDATE; + m.flags_ = 0; else if (action == UP_OBJ_FACE) /* Nothing to do for that case */ ; else @@ -697,7 +660,6 @@ update_object (op->more, action); } -object::vector object::objects; // not yet used object *object::first; object::object () @@ -715,40 +677,36 @@ void object::link () { - count = ++ob_count; uuid = gen_uuid (); - prev = 0; - next = object::first; - - if (object::first) - object::first->prev = this; - - object::first = this; + refcnt_inc (); + objects.insert (this); } void object::unlink () { - if (this == object::first) - object::first = next; + objects.erase (this); + refcnt_dec (); +} - /* Remove this object from the list of used objects */ - if (prev) prev->next = next; - if (next) next->prev = prev; +void +object::activate () +{ + /* If already on active list, don't do anything */ + if (active) + return; - prev = 0; - next = 0; + if (has_active_speed ()) + actives.insert (this); } void -object::activate (bool recursive) +object::activate_recursive () { - // uh, hack - set_speed (speed); + activate (); - if (recursive) - for (object *op = inv; op; op = op->above) - op->activate (1); + for (object *op = inv; op; op = op->below) + op->activate_recursive (); } /* This function removes object 'op' from the list of active @@ -760,31 +718,32 @@ * will do the right thing based on the speed of the object. */ void -object::deactivate (bool recursive) +object::deactivate () { /* If not on the active list, nothing needs to be done */ - if (!active_next && !active_prev && this != active_objects) + if (!active) return; - if (active_prev == 0) - { - active_objects = active_next; - if (active_next) - active_next->active_prev = 0; - } - else - { - active_prev->active_next = active_next; - if (active_next) - active_next->active_prev = active_prev; - } + actives.erase (this); +} + +void +object::deactivate_recursive () +{ + for (object *op = inv; op; op = op->below) + op->deactivate_recursive (); - active_next = 0; - active_prev = 0; + deactivate (); +} - if (recursive) - for (object *op = inv; op; op = op->above) - op->deactivate (1); +void +object::set_flag_inv (int flag, int value) +{ + for (object *op = inv; op; op = op->below) + { + op->flag [flag] = value; + op->set_flag_inv (flag, value); + } } /* @@ -827,7 +786,8 @@ || op->flag [FLAG_NO_DROP] || op->type == RUNE || op->type == TRAP - || op->flag [FLAG_IS_A_TEMPLATE]) + || op->flag [FLAG_IS_A_TEMPLATE] + || op->flag [FLAG_DESTROY_ON_DEATH]) op->destroy (); else map->insert (op, x, y); @@ -879,6 +839,7 @@ freed_map->height = 3; freed_map->alloc (); + freed_map->in_memory = MAP_IN_MEMORY; } map = freed_map; @@ -898,9 +859,6 @@ owner = 0; enemy = 0; attacked_by = 0; - - // only relevant for players(?), but make sure of it anyways - contr = 0; } void @@ -995,9 +953,10 @@ if (type == PLAYER) { --map->players; - map->last_access = runtime; + map->touch (); } + map->dirty = true; /* link the object above us */ if (above) @@ -1080,7 +1039,7 @@ /* 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_ = P_NEED_UPDATE; + map->at (x, y).flags_ = 0; else update_object (last, UP_OBJ_REMOVE); @@ -1211,10 +1170,10 @@ object *more = op->more; - /* We really need the caller to normalize coordinates - if + /* We really need the caller to normalise coordinates - if * we set the map, that doesn't work if the location is within * a map and this is straddling an edge. So only if coordinate - * is clear wrong do we normalize it. + * is clear wrong do we normalise it. */ if (OUT_OF_REAL_MAP (more->map, more->x, more->y)) more->map = get_map_from_coord (m, &more->x, &more->y); @@ -1384,9 +1343,11 @@ { op->contr->do_los = 1; ++op->map->players; - op->map->last_access = runtime; + op->map->touch (); } + 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. */ @@ -1401,7 +1362,7 @@ * on the map will get recalculated. The players could very well * be far away from this change and not affected in any way - * this should get redone to only look for players within range, - * or just updating the P_NEED_UPDATE for spaces within this area + * or just updating the P_UPTODATE for spaces within this area * of effect may be sufficient. */ if (op->map->darkness && (op->glow_radius != 0)) @@ -1449,7 +1410,7 @@ /* first search for itself and remove any old instances */ - for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) + for (tmp = op->ms ().bot; tmp; tmp = tmp->above) if (!strcmp (tmp->arch->name, arch_string)) /* same archetype */ tmp->destroy (); @@ -1782,7 +1743,7 @@ * Hence, we first go to the top: */ - for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp && tmp->above; tmp = tmp->above) + for (tmp = op->ms ().bot; tmp && tmp->above; tmp = tmp->above) { /* Trim the search when we find the first other spell effect * this helps performance so that if a space has 50 spell objects, @@ -1850,13 +1811,13 @@ object * present_arch (const archetype *at, maptile *m, int x, int y) { - if (m == NULL || out_of_map (m, x, y)) + if (!m || out_of_map (m, x, y)) { LOG (llevError, "Present_arch called outside map.\n"); return NULL; } - for (object *tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) + for (object *tmp = m->at (x, y).bot; tmp; tmp = tmp->above) if (tmp->arch == at) return tmp; @@ -1877,7 +1838,7 @@ return NULL; } - for (object *tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) + for (object *tmp = m->at (x, y).bot; tmp; tmp = tmp->above) if (tmp->type == type) return tmp; @@ -2612,18 +2573,49 @@ item = item->env; } -// return a suitable string describing an objetc in enough detail to find it + +const char * +object::flag_desc (char *desc, int len) const +{ + char *p = desc; + bool first = true; + + *p = 0; + + for (int i = 0; i < NUM_FLAGS; i++) + { + if (len <= 10) // magic constant! + { + snprintf (p, len, ",..."); + break; + } + + if (flag [i]) + { + int cnt = snprintf (p, len, "%s%d", first ? "" : ",", i); + len -= cnt; + p += cnt; + first = false; + } + } + + return desc; +} + +// return a suitable string describing an object in enough detail to find it const char * object::debug_desc (char *info) const { - char info2[256 * 3]; + char flagdesc[512]; + char info2[256 * 4]; char *p = info; - p += snprintf (p, 256, "%d=\"%s%s%s\"", - count, + p += snprintf (p, 512, "{cnt:%d,uuid:<1,%" PRIx64 ">,name:\"%s%s%s\",flags:[%s],type:%d}", + count, uuid.seq, &name, - title ? " " : "", - title ? (const char *)title : ""); + title ? "\",title:" : "", + title ? (const char *)title : "", + flag_desc (flagdesc, 512), type); if (env) p += snprintf (p, 256, "(in %s)", env->debug_desc (info2)); @@ -2637,7 +2629,7 @@ const char * object::debug_desc () const { - static char info[256 * 3]; + static char info[256 * 4]; return debug_desc (info); }