--- deliantra/server/common/object.C 2007/01/02 21:13:21 1.104 +++ deliantra/server/common/object.C 2007/01/24 22:42:48 1.122 @@ -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; @@ -491,7 +491,7 @@ SET_FLAG (dst, FLAG_REMOVED); if (speed < 0) - dst->speed_left = speed_left - RANDOM () % 200 / 100.0; + dst->speed_left = speed_left - rndm (); /* Copy over key_values, if any. */ if (key_values) @@ -662,8 +662,6 @@ update_object (op->more, action); } -object *object::first; - object::object () { SET_FLAG (this, FLAG_REMOVED); @@ -674,60 +672,41 @@ object::~object () { + unlink (); + 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; -} + if (!index) + return; -bool -object::active () const -{ - return active_next || active_prev || this == active_objects; + objects.erase (this); + refcnt_dec (); } void object::activate () { /* If already on active list, don't do anything */ - if (active ()) + if (active) return; if (has_active_speed ()) - { - /* 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; - } + actives.insert (this); } void @@ -751,24 +730,10 @@ object::deactivate () { /* If not on the active list, nothing needs to be done */ - if (!active ()) + 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; - } - - active_next = 0; - active_prev = 0; + actives.erase (this); } void @@ -780,6 +745,16 @@ 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); + } +} + /* * Remove and free all objects in the inventory of the given object. * object.c ? @@ -802,6 +777,7 @@ if (!drop_to_ground || !map || map->in_memory != MAP_IN_MEMORY + || map->nodrop || ms ().move_block == MOVE_ALL) { while (inv) @@ -820,7 +796,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); @@ -838,6 +815,8 @@ void object::do_destroy () { + attachable::do_destroy (); + if (flag [FLAG_IS_LINKED]) remove_button_link (this); @@ -847,18 +826,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 @@ -892,9 +866,6 @@ owner = 0; enemy = 0; attacked_by = 0; - - // only relevant for players(?), but make sure of it anyways - contr = 0; } void @@ -935,7 +906,7 @@ * Beware: This function is called from the editor as well! */ void -object::remove () +object::remove_slow () { object *tmp, *last = 0; object *otmp; @@ -993,12 +964,13 @@ } map->dirty = true; + mapspace &ms = this->ms (); /* link the object above us */ if (above) above->below = below; else - map->at (x, y).top = below; /* we were top, set new top */ + ms.top = below; /* we were top, set new top */ /* Relink the object below us, if there is one */ if (below) @@ -1010,17 +982,9 @@ * evident */ if (GET_MAP_OB (map, x, y) != this) - { - char *dump = dump_object (this); - LOG (llevError, - "remove_ob: GET_MAP_OB does not return object to be removed even though it appears to be on the bottom?\n%s\n", dump); - free (dump); - dump = dump_object (GET_MAP_OB (map, x, y)); - LOG (llevError, "%s\n", dump); - free (dump); - } + LOG (llevError, "remove_ob: GET_MAP_OB does not return object to be removed even though it appears to be on the bottom? %s\n", debug_desc ()); - map->at (x, y).bot = above; /* goes on above it. */ + ms.bot = above; /* goes on above it. */ } above = 0; @@ -1031,7 +995,7 @@ int check_walk_off = !flag [FLAG_NO_APPLY]; - for (tmp = map->at (x, y).bot; tmp; tmp = tmp->above) + for (tmp = ms.bot; tmp; tmp = tmp->above) { /* No point updating the players look faces if he is the object * being removed. @@ -1122,8 +1086,8 @@ } /* - * same as insert_ob_in_map except it handle separate coordinates and do a clean - * job preparing multi-part monsters + * same as insert_ob_in_map except it handles separate coordinates and does a clean + * job preparing multi-part monsters. */ object * insert_ob_in_map_at (object *op, maptile *m, object *originator, int flag, int x, int y) @@ -1161,7 +1125,6 @@ insert_ob_in_map (object *op, maptile *m, object *originator, int flag) { object *tmp, *top, *floor = NULL; - sint16 x, y; if (QUERY_FLAG (op, FLAG_FREED)) { @@ -1169,6 +1132,11 @@ return NULL; } + if (!QUERY_FLAG (op, FLAG_REMOVED)) + LOG (llevError, "Trying to insert already inserted object %s\n", op->debug_desc ()); + + op->remove (); + if (!m) { char *dump = dump_object (op); @@ -1192,36 +1160,9 @@ return op; } - if (!QUERY_FLAG (op, FLAG_REMOVED)) + if (object *more = op->more) { - char *dump = dump_object (op); - LOG (llevError, "Trying to insert (map) inserted object.\n%s\n", dump); - free (dump); - return op; - } - - if (op->more) - { - /* The part may be on a different map. */ - - object *more = op->more; - - /* We really need the caller to normalize 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. - */ - if (OUT_OF_REAL_MAP (more->map, more->x, more->y)) - more->map = get_map_from_coord (m, &more->x, &more->y); - else if (!more->map) - { - /* For backwards compatibility - when not dealing with tiled maps, - * more->map should always point to the parent. - */ - more->map = m; - } - - if (insert_ob_in_map (more, more->map, originator, flag) == NULL) + if (!insert_ob_in_map (more, m, originator, flag)) { if (!op->head) LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); @@ -1236,14 +1177,16 @@ * of areas of callers (eg, anything that uses find_free_spot would now * need extra work */ - op->map = get_map_from_coord (m, &op->x, &op->y); - x = op->x; - y = op->y; + if (!xy_normalise (m, op->x, op->y)) + return 0; + + op->map = m; + mapspace &ms = op->ms (); /* this has to be done after we translate the coordinates. */ if (op->nrof && !(flag & INS_NO_MERGE)) - for (tmp = GET_MAP_OB (op->map, x, y); tmp; tmp = tmp->above) + for (tmp = ms.bot; tmp; tmp = tmp->above) if (object::can_merge (op, tmp)) { op->nrof += tmp->nrof; @@ -1270,15 +1213,17 @@ if (op->below) op->below->above = op; else - op->ms ().bot = op; + ms.bot = op; /* since *below* originator, no need to update top */ originator->below = op; } else { + top = ms.bot; + /* If there are other objects, then */ - if ((!(flag & INS_MAP_LOAD)) && ((top = GET_MAP_OB (op->map, op->x, op->y)) != NULL)) + if ((!(flag & INS_MAP_LOAD)) && top) { object *last = 0; @@ -1294,7 +1239,7 @@ * when lots of spells are cast in one area. Currently, it is presumed * that flying non pickable objects are spell objects. */ - while (top) + for (top = ms.bot; top; top = top->above) { if (QUERY_FLAG (top, FLAG_IS_FLOOR) || QUERY_FLAG (top, FLAG_OVERLAY_FLOOR)) floor = top; @@ -1307,7 +1252,6 @@ } last = top; - top = top->above; } /* Don't want top to be NULL, so set it to the last valid object */ @@ -1324,12 +1268,14 @@ * Need to find the object that in fact blocks view, otherwise * stacking is a bit odd. */ - if (!(flag & INS_ON_TOP) && - (get_map_flags (op->map, 0, op->x, op->y, 0, 0) & P_BLOCKSVIEW) && (op->face && !op->face->visibility)) + if (!(flag & INS_ON_TOP) + && ms.flags () & P_BLOCKSVIEW + && (op->face && !op->face->visibility)) { for (last = top; last != floor; last = last->below) if (QUERY_FLAG (last, FLAG_BLOCKSVIEW) && (last->type != EXIT)) break; + /* Check to see if we found the object that blocks view, * and make sure we have a below pointer for it so that * we can get inserted below this one, which requires we @@ -1341,7 +1287,7 @@ } /* If objects on this space */ if (flag & INS_MAP_LOAD) - top = GET_MAP_TOP (op->map, op->x, op->y); + top = ms.top; if (flag & INS_ABOVE_FLOOR_ONLY) top = floor; @@ -1352,13 +1298,13 @@ /* First object on this space */ if (!top) { - op->above = GET_MAP_OB (op->map, op->x, op->y); + op->above = ms.bot; if (op->above) op->above->below = op; op->below = 0; - op->ms ().bot = op; + ms.bot = op; } else { /* get inserted into the stack above top */ @@ -1372,7 +1318,7 @@ } if (!op->above) - op->ms ().top = op; + ms.top = op; } /* else not INS_BELOW_ORIGINATOR */ if (op->type == PLAYER) @@ -1388,7 +1334,7 @@ * it, so save a few ticks and start from there. */ if (!(flag & INS_MAP_LOAD)) - if (object *pl = op->ms ().player ()) + if (object *pl = ms.player ()) if (pl->contr->ns) pl->contr->ns->floorbox_update (); @@ -1807,7 +1753,7 @@ { float - diff = tmp->move_slow_penalty * FABS (op->speed); + diff = tmp->move_slow_penalty * fabs (op->speed); if (op->type == PLAYER) if ((QUERY_FLAG (tmp, FLAG_IS_HILLY) && find_skill_by_number (op, SK_CLIMBING)) || @@ -2199,28 +2145,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) { @@ -2646,10 +2573,10 @@ char info2[256 * 4]; char *p = info; - p += snprintf (p, 512, "{cnt:%d,uuid:<1,%" PRIx64 ">,name:\"%s%s%s\",flags:[%s],type:%d}", + p += snprintf (p, 512, "{cnt:%d,uuid:<1,%" PRIx64 ">,name:\"%s\"%s%s,flags:[%s],type:%d}", count, uuid.seq, &name, - title ? "\",title:" : "", + title ? "\",title:\"" : "", title ? (const char *)title : "", flag_desc (flagdesc, 512), type); @@ -2667,5 +2594,12 @@ { static char info[256 * 4]; return debug_desc (info); +} + +const char * +object::debug_desc2 () const +{ + static char info[256 * 4]; + return debug_desc (info); }