--- deliantra/server/common/object.C 2006/12/30 21:07:46 1.97 +++ deliantra/server/common/object.C 2007/01/15 21:06:18 1.116 @@ -1,25 +1,26 @@ /* - CrossFire, A Multiplayer game for X-windows - - Copyright (C) 2001 Mark Wedel & Crossfire Development Team - Copyright (C) 1992 Frank Tore Johansen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - The authors can be reached via e-mail at -*/ + * 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * The authors can be reached via e-mail at + */ /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects. sub/add_weight will transcend the environment updating the carrying @@ -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 @@ -392,13 +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; + for_all_objects (op) + if (op->count == i) + return op; return 0; } @@ -408,14 +409,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; @@ -566,9 +566,9 @@ this->speed = speed; if (has_active_speed ()) - activate (false); + activate (); else - deactivate (false); + deactivate (); } /* @@ -626,7 +626,7 @@ mapspace &m = op->ms (); - if (m.flags_ & P_NEED_UPDATE) + if (!(m.flags_ & P_UPTODATE)) /* nop */; else if (action == UP_OBJ_INSERT) { @@ -645,14 +645,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 @@ -662,9 +662,6 @@ update_object (op->more, action); } -object::vector object::objects; // not yet used -object *object::first; - object::object () { SET_FLAG (this, FLAG_REMOVED); @@ -678,55 +675,43 @@ free_key_values (this); } +static int object_count; + void object::link () { - count = ++ob_count; + assert (!index);//D uuid = gen_uuid (); + count = ++object_count; - 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; - - /* Remove this object from the list of used objects */ - if (prev) prev->next = next; - if (next) next->prev = prev; - - prev = 0; - next = 0; + assert (index);//D + objects.erase (this); + refcnt_dec (); } void -object::activate (bool recursive) +object::activate () { - if (has_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 already on active list, don't do anything */ + if (active) + return; - if (active_next) - active_next->active_prev = this; + if (has_active_speed ()) + actives.insert (this); +} - active_objects = this; - } +void +object::activate_recursive () +{ + 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 @@ -738,31 +723,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); +} - active_next = 0; - active_prev = 0; +void +object::deactivate_recursive () +{ + for (object *op = inv; op; op = op->below) + op->deactivate_recursive (); - if (recursive) - for (object *op = inv; op; op = op->above) - op->deactivate (1); + deactivate (); +} + +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); + } } /* @@ -805,7 +791,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); @@ -823,6 +810,8 @@ void object::do_destroy () { + attachable::do_destroy (); + if (flag [FLAG_IS_LINKED]) remove_button_link (this); @@ -832,18 +821,13 @@ if (!flag [FLAG_REMOVED]) remove (); - if (flag [FLAG_FREED]) - return; + destroy_inv (true); - set_speed (0); + deactivate (); + unlink (); flag [FLAG_FREED] = 1; - attachable::do_destroy (); - - destroy_inv (true); - unlink (); - // hack to ensure that freed objects still have a valid map { static maptile *freed_map; // freed objects are moved here to avoid crashes @@ -857,6 +841,7 @@ freed_map->height = 3; freed_map->alloc (); + freed_map->in_memory = MAP_IN_MEMORY; } map = freed_map; @@ -876,9 +861,6 @@ owner = 0; enemy = 0; attacked_by = 0; - - // only relevant for players(?), but make sure of it anyways - contr = 0; } void @@ -973,9 +955,10 @@ if (type == PLAYER) { --map->players; - map->last_access = runtime; + map->touch (); } + map->dirty = true; /* link the object above us */ if (above) @@ -1058,7 +1041,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); @@ -1189,10 +1172,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); @@ -1362,9 +1345,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. */ @@ -1379,7 +1364,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)) @@ -1427,7 +1412,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 (); @@ -1760,7 +1745,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, @@ -1828,13 +1813,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; @@ -1855,7 +1840,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; @@ -2180,28 +2165,9 @@ } /* - * absdir(int): Returns a number between 1 and 8, which represent - * the "absolute" direction of a number (it actually takes care of - * "overflow" in previous calculations of a direction). - */ - -int -absdir (int d) -{ - while (d < 1) - d += 8; - - while (d > 8) - d -= 8; - - return d; -} - -/* * dirdiff(dir1, dir2) returns how many 45-degrees differences there is * between two directions (which are expected to be absolute (see absdir()) */ - int dirdiff (int dir1, int dir2) { @@ -2597,6 +2563,8 @@ char *p = desc; bool first = true; + *p = 0; + for (int i = 0; i < NUM_FLAGS; i++) { if (len <= 10) // magic constant! @@ -2605,7 +2573,7 @@ break; } - if (flag[i]) + if (flag [i]) { int cnt = snprintf (p, len, "%s%d", first ? "" : ",", i); len -= cnt; @@ -2617,7 +2585,7 @@ return desc; } -// return a suitable string describing an objetc in enough detail to find it +// return a suitable string describing an object in enough detail to find it const char * object::debug_desc (char *info) const { @@ -2644,7 +2612,14 @@ const char * object::debug_desc () const { - static char info[256 * 3]; + static char info[256 * 4]; + return debug_desc (info); +} + +const char * +object::debug_desc2 () const +{ + static char info[256 * 4]; return debug_desc (info); }