--- deliantra/server/common/object.C 2006/12/20 11:36:38 1.75 +++ deliantra/server/common/object.C 2006/12/25 14:54:44 1.84 @@ -223,7 +223,7 @@ if (QUERY_FLAG (ob2, FLAG_IDENTIFIED)) SET_FLAG (ob2, FLAG_BEEN_APPLIED); - if ((ob1->flags ^ ob2->flags).reset (FLAG_INV_LOCKED).reset (FLAG_CLIENT_SENT).any () + if ((ob1->flag ^ ob2->flag).reset (FLAG_INV_LOCKED).reset (FLAG_CLIENT_SENT).any () || ob1->arch != ob2->arch || ob1->name != ob2->name || ob1->title != ob2->title @@ -469,48 +469,6 @@ op->key_values = 0; } -void object::clear () -{ - attachable_base::clear (); - - free_key_values (this); - - owner = 0; - name = 0; - name_pl = 0; - title = 0; - race = 0; - slaying = 0; - skill = 0; - msg = 0; - lore = 0; - custom_name = 0; - materialname = 0; - contr = 0; - below = 0; - above = 0; - inv = 0; - container = 0; - env = 0; - more = 0; - head = 0; - map = 0; - active_next = 0; - active_prev = 0; - - memset (static_cast(this), 0, sizeof (object_pod)); - - SET_FLAG (this, FLAG_REMOVED); - - /* What is not cleared is next, prev, and count */ - - expmul = 1.0; - face = blank_face; - - if (settings.casting_time) - casting_time = -1; -} - /* * copy_to first frees everything allocated by the dst object, * and then copies the contents of itself into the second @@ -526,10 +484,6 @@ bool is_removed = QUERY_FLAG (dst, FLAG_REMOVED); *(object_copy *)dst = *this; - *(object_pod *)dst = *this; - - if (self || cb) - INVOKE_OBJECT (CLONE, this, ARG_OBJECT (dst)); if (is_freed) SET_FLAG (dst, FLAG_FREED); @@ -739,7 +693,7 @@ return; /* make sure the object is within map boundaries */ - if (op->x < 0 || op->x >= MAP_WIDTH (op->map) || op->y < 0 || op->y >= MAP_HEIGHT (op->map)) + if (op->x < 0 || op->x >= op->map->width || op->y < 0 || op->y >= op->map->height) { LOG (llevError, "update_object() called for object out of map!\n"); #ifdef MANY_CORES @@ -748,7 +702,7 @@ return; } - mapspace &m = op->map->at (op->x, op->y); + mapspace &m = op->ms (); if (m.flags_ & P_NEED_UPDATE) /* nop */; @@ -786,22 +740,9 @@ update_object (op->more, action); } -object::vector object::mortals; object::vector object::objects; // not yet used object *object::first; -void object::free_mortals () -{ - for (AUTODECL (i, mortals.begin ()); i != mortals.end ();) - if ((*i)->refcnt) - ++i; // further delay freeing - else - { - delete *i; - mortals.erase (i); - } -} - object::object () { SET_FLAG (this, FLAG_REMOVED); @@ -859,66 +800,24 @@ * If destroy_inventory is set, free inventory as well. Else drop items in * inventory to the ground. */ -void object::destroy (bool destroy_inventory) +void +object::do_destroy () { - if (QUERY_FLAG (this, FLAG_FREED)) - return; + attachable::do_destroy (); - if (QUERY_FLAG (this, FLAG_FRIENDLY)) + if (flag [FLAG_IS_LINKED]) + remove_button_link (this); + + if (flag [FLAG_FRIENDLY]) remove_friendly_object (this); - if (!QUERY_FLAG (this, FLAG_REMOVED)) + if (!flag [FLAG_REMOVED]) remove (); - SET_FLAG (this, FLAG_FREED); - - if (more) - { - more->destroy (destroy_inventory); - more = 0; - } - - if (inv) - { - /* Only if the space blocks everything do we not process - - * if some form of movement is allowed, let objects - * drop on that space. - */ - if (destroy_inventory || !map || map->in_memory != MAP_IN_MEMORY || GET_MAP_MOVE_BLOCK (map, x, y) == MOVE_ALL) - { - object *op = inv; - - while (op) - { - object *tmp = op->below; - op->destroy (destroy_inventory); - op = tmp; - } - } - else - { /* Put objects in inventory onto this space */ - object *op = inv; - - while (op) - { - object *tmp = op->below; + if (flag [FLAG_FREED]) + return; - op->remove (); - - if (QUERY_FLAG (op, FLAG_STARTEQUIP) - || QUERY_FLAG (op, FLAG_NO_DROP) || op->type == RUNE || op->type == TRAP || QUERY_FLAG (op, FLAG_IS_A_TEMPLATE)) - op->destroy (); - else - { - op->x = x; - op->y = y; - insert_ob_in_map (op, map, 0, 0); /* Insert in same map as the envir */ - } - - op = tmp; - } - } - } + flag [FLAG_FREED] = 1; // hack to ensure that freed objects still have a valid map { @@ -940,6 +839,10 @@ y = 1; } + more = 0; + head = 0; + inv = 0; + // clear those pointers that likely might have circular references to us owner = 0; enemy = 0; @@ -953,8 +856,70 @@ update_ob_speed (this); unlink (); +} + +/* + * Remove and free all objects in the inventory of the given object. + * object.c ? + */ +void +object::destroy_inv (bool drop_to_ground) +{ + if (!inv) + return; + + /* Only if the space blocks everything do we not process - + * if some form of movement is allowed, let objects + * drop on that space. + */ + if (!drop_to_ground || !map || map->in_memory != MAP_IN_MEMORY || GET_MAP_MOVE_BLOCK (map, x, y) == MOVE_ALL) + { + while (inv) + { + inv->destroy_inv (drop_to_ground); + inv->destroy (); + } + } + else + { /* Put objects in inventory onto this space */ + while (inv) + { + object *op = inv; + + if (op->flag [FLAG_STARTEQUIP] + || op->flag [FLAG_NO_DROP] + || op->type == RUNE + || op->type == TRAP + || op->flag [FLAG_IS_A_TEMPLATE]) + op->destroy (); + else + { + op->remove (); + op->x = x; + op->y = y; + insert_ob_in_map (op, map, 0, 0); /* Insert in same map as the envir */ + } + } + } +} + +void +object::destroy (bool destroy_inventory) +{ + if (destroyed ()) + return; - mortals.push_back (this); + if (more) + { + //TODO: non-head objects must not have inventory + more->destroy (destroy_inventory); + more = 0; + } + + if (destroy_inventory) + destroy_inv (true); + + attachable::destroy (); } /* @@ -988,12 +953,11 @@ object *tmp, *last = 0; object *otmp; - int check_walk_off; - if (QUERY_FLAG (this, FLAG_REMOVED)) return; SET_FLAG (this, FLAG_REMOVED); + INVOKE_OBJECT (REMOVE, this); if (more) more->remove (); @@ -1014,7 +978,7 @@ * to save cpu time. */ if ((otmp = in_player ()) && otmp->contr && !QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) - fix_player (otmp); + otmp->update_stats (); if (above != NULL) above->below = below; @@ -1065,7 +1029,7 @@ free (dump); } - map->at (x, y).bottom = above; /* goes on above it. */ + map->at (x, y).bot = above; /* goes on above it. */ } above = 0; @@ -1074,7 +1038,7 @@ if (map->in_memory == MAP_SAVING) return; - check_walk_off = !QUERY_FLAG (this, FLAG_NO_APPLY); + int check_walk_off = !flag [FLAG_NO_APPLY]; for (tmp = GET_MAP_OB (map, x, y); tmp; tmp = tmp->above) { @@ -1090,11 +1054,12 @@ */ if (tmp->container == this) { - CLEAR_FLAG (this, FLAG_APPLIED); + flag [FLAG_APPLIED] = 0; tmp->container = 0; } - tmp->contr->socket->floorbox_update (); + if (tmp->contr->ns) + tmp->contr->ns->floorbox_update (); } /* See if player moving off should effect something */ @@ -1122,7 +1087,7 @@ else update_object (last, UP_OBJ_REMOVE); - if (QUERY_FLAG (this, FLAG_BLOCKSVIEW) || glow_radius) + if (flag [FLAG_BLOCKSVIEW] || glow_radius) update_all_los (map, x, y); } } @@ -1141,10 +1106,11 @@ if (!op->nrof) return 0; - if (top == NULL) - for (top = op; top != NULL && top->above != NULL; top = top->above); + if (top) + for (top = op; top && top->above; top = top->above) + ; - for (; top != NULL; top = top->below) + for (; top; top = top->below) { if (top == op) continue; @@ -1204,7 +1170,6 @@ * NULL if 'op' was destroyed * just 'op' otherwise */ - object * insert_ob_in_map (object *op, maptile *m, object *originator, int flag) { @@ -1248,7 +1213,7 @@ return op; } - if (op->more != NULL) + if (op->more) { /* The part may be on a different map. */ @@ -1274,7 +1239,7 @@ if (!op->head) LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); - return NULL; + return 0; } } @@ -1318,7 +1283,7 @@ if (op->below) op->below->above = op; else - op->map->at (op->x, op->y).bottom = op; + op->ms ().bot = op; /* since *below* originator, no need to update top */ originator->below = op; @@ -1407,7 +1372,7 @@ op->above->below = op; op->below = NULL; - op->map->at (op->x, op->y).bottom = op; + op->ms ().bot = op; } else { /* get inserted into the stack above top */ @@ -1421,7 +1386,7 @@ } if (op->above == NULL) - op->map->at (op->x, op->y).top = op; + op->ms ().top = op; } /* else not INS_BELOW_ORIGINATOR */ if (op->type == PLAYER) @@ -1431,8 +1396,9 @@ * it, so save a few ticks and start from there. */ if (!(flag & INS_MAP_LOAD)) - if (object *pl = op->map->at (op->x, op->y).player ()) - pl->contr->socket->floorbox_update (); + if (object *pl = op->ms ().player ()) + if (pl->contr->ns) + 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 @@ -1443,12 +1409,14 @@ * or just updating the P_NEED_UPDATE for spaces within this area * of effect may be sufficient. */ - if (MAP_DARKNESS (op->map) && (op->glow_radius != 0)) + if (op->map->darkness && (op->glow_radius != 0)) 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); + INVOKE_OBJECT (INSERT, op); + /* Don't know if moving this to the end will break anything. However, * we want to have floorbox_update called before calling this. * @@ -1462,14 +1430,14 @@ if (!(flag & INS_NO_WALK_ON) && !op->head) { if (check_move_on (op, originator)) - return NULL; + return 0; /* If we are a multi part object, lets work our way through the check * walk on's. */ for (tmp = op->more; tmp != NULL; tmp = tmp->more) if (check_move_on (tmp, originator)) - return NULL; + return 0; } return op; @@ -1550,7 +1518,6 @@ decrease_ob_nr (object *op, uint32 i) { object *tmp; - player *pl; if (i == 0) /* objects with op->nrof require this check */ return op; @@ -1573,14 +1540,12 @@ * and then searching the map for a player. */ if (!tmp) - { - for (pl = first_player; pl; pl = pl->next) - if (pl->ob->container == op->env) - { - tmp = pl->ob; - break; - } - } + for_all_players (pl) + if (pl->ob->container == op->env) + { + tmp = pl->ob; + break; + } if (i < op->nrof) { @@ -1726,7 +1691,7 @@ otmp = this->in_player (); if (otmp && otmp->contr) if (!QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER)) - fix_player (otmp); + otmp->update_stats (); op->map = 0; op->env = this; @@ -1740,7 +1705,7 @@ #ifdef DEBUG_LIGHTS LOG (llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n", op->name); #endif /* DEBUG_LIGHTS */ - if (MAP_DARKNESS (map)) + if (map->darkness) update_all_los (map, x, y); } @@ -1756,6 +1721,8 @@ inv = op; } + INVOKE_OBJECT (INSERT, this); + return op; } @@ -1816,7 +1783,7 @@ * Hence, we first go to the top: */ - for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL && tmp->above != NULL; tmp = tmp->above) + for (tmp = GET_MAP_OB (op->map, op->x, op->y); 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, @@ -1881,21 +1848,19 @@ * a matching archetype at the given map and coordinates. * The first matching object is returned, or NULL if none. */ - object * present_arch (const archetype *at, maptile *m, int x, int y) { - object * - tmp; - if (m == NULL || out_of_map (m, x, y)) { LOG (llevError, "Present_arch called outside map.\n"); return NULL; } - for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) + + for (object *tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) if (tmp->arch == at) return tmp; + return NULL; } @@ -1904,21 +1869,19 @@ * a matching type variable at the given map and coordinates. * The first matching object is returned, or NULL if none. */ - object * present (unsigned char type, maptile *m, int x, int y) { - object * - tmp; - if (out_of_map (m, x, y)) { LOG (llevError, "Present called outside map.\n"); return NULL; } - for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) + + for (object *tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) if (tmp->type == type) return tmp; + return NULL; } @@ -1927,16 +1890,13 @@ * a matching type variable in the inventory of the given object. * The first matching object is returned, or NULL if none. */ - object * present_in_ob (unsigned char type, const object *op) { - object * - tmp; - - for (tmp = op->inv; tmp != NULL; tmp = tmp->below) + for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) if (tmp->type == type) return tmp; + return NULL; } @@ -1954,19 +1914,14 @@ * spell code can use one object type (force), but change it's name * to be unique. */ - object * present_in_ob_by_name (int type, const char *str, const object *op) { - object * - tmp; + for (object *tmp = op->inv; tmp; tmp = tmp->below) + if ((type == -1 || tmp->type == type) && (!strcmp (str, tmp->name))) + return tmp; - for (tmp = op->inv; tmp != NULL; tmp = tmp->below) - { - if ((type == -1 || tmp->type == type) && (!strcmp (str, tmp->name))) - return tmp; - } - return NULL; + return 0; } /* @@ -1974,16 +1929,13 @@ * a matching archetype in the inventory of the given object. * The first matching object is returned, or NULL if none. */ - object * present_arch_in_ob (const archetype *at, const object *op) { - object * - tmp; - - for (tmp = op->inv; tmp != NULL; tmp = tmp->below) + for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) if (tmp->arch == at) return tmp; + return NULL; } @@ -1993,26 +1945,22 @@ void flag_inv (object *op, int flag) { - object * - tmp; - if (op->inv) - for (tmp = op->inv; tmp != NULL; tmp = tmp->below) + for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) { SET_FLAG (tmp, flag); flag_inv (tmp, flag); } -} /* - * desactivate recursively a flag on an object inventory - */ +} + +/* + * deactivate recursively a flag on an object inventory + */ void unflag_inv (object *op, int flag) { - object * - tmp; - if (op->inv) - for (tmp = op->inv; tmp != NULL; tmp = tmp->below) + for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) { CLEAR_FLAG (tmp, flag); unflag_inv (tmp, flag); @@ -2025,7 +1973,6 @@ * If checksums are used, a player will get set_cheat called for * him/her-self and all object carried by a call to this function. */ - void set_cheat (object *op) { @@ -2054,21 +2001,17 @@ * the archetype because that isn't correct if the monster has been * customized, changed states, etc. */ - int find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop) { - int - i, - index = 0, flag; - static int - altern[SIZEOFFREE]; + int index = 0, flag; + int altern[SIZEOFFREE]; - for (i = start; i < stop; i++) + 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; + altern [index++] = i; /* 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. @@ -2094,43 +2037,29 @@ * But it will return the first available spot, not a random choice. * Changed 0.93.2: Have it return -1 if there is no free spot available. */ - int find_first_free_spot (const object *ob, maptile *m, int x, int y) { - int - i; + for (int i = 0; i < SIZEOFFREE; i++) + if (!ob_blocked (ob, m, x + freearr_x[i], y + freearr_y[i])) + return i; - for (i = 0; i < SIZEOFFREE; i++) - { - if (!ob_blocked (ob, m, x + freearr_x[i], y + freearr_y[i])) - return i; - } return -1; } /* * The function permute(arr, begin, end) randomly reorders the array * arr[begin..end-1]. + * now uses a fisher-yates shuffle, old permute was broken */ static void permute (int *arr, int begin, int end) { - int - i, - j, - tmp, - len; - - len = end - begin; - for (i = begin; i < end; i++) - { - j = begin + RANDOM () % len; - - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } + arr += begin; + end -= begin; + + while (--end) + swap (arr [end], arr [RANDOM () % (end + 1)]); } /* new function to make monster searching more efficient, and effective! @@ -2143,13 +2072,10 @@ void get_search_arr (int *search_arr) { - int - i; + int i; for (i = 0; i < SIZEOFFREE; i++) - { - search_arr[i] = i; - } + search_arr[i] = i; permute (search_arr, 1, SIZEOFFREE1 + 1); permute (search_arr, SIZEOFFREE1 + 1, SIZEOFFREE2 + 1); @@ -2168,19 +2094,14 @@ * because we have to know what movement the thing looking to move * there is capable of. */ - int find_dir (maptile *m, int x, int y, object *exclude) { - int - i, - max = SIZEOFFREE, mflags; + int i, max = SIZEOFFREE, mflags; sint16 nx, ny; - object * - tmp; - maptile * - mp; + object *tmp; + maptile *mp; MoveType blocked, move_type; @@ -2207,14 +2128,17 @@ max = maxfree[i]; else { - blocked = GET_MAP_MOVE_BLOCK (mp, nx, ny); + mapspace &ms = mp->at (nx, ny); + + blocked = ms.move_block; if ((move_type & blocked) == move_type) max = maxfree[i]; else if (mflags & P_IS_ALIVE) { - for (tmp = GET_MAP_OB (mp, nx, ny); tmp; tmp = tmp->above) - if ((QUERY_FLAG (tmp, FLAG_MONSTER) || tmp->type == PLAYER) && (tmp != exclude || (tmp->head && tmp->head != exclude))) + for (tmp = ms.bot; tmp; tmp = tmp->above) + if ((tmp->flag [FLAG_MONSTER] || tmp->type == PLAYER) + && (tmp != exclude || (tmp->head && tmp->head != exclude))) break; if (tmp) @@ -2230,14 +2154,10 @@ * distance(object 1, object 2) will return the square of the * distance between the two given objects. */ - int distance (const object *ob1, const object *ob2) { - int i; - - i = (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y); - return i; + return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y); } /* @@ -2245,7 +2165,6 @@ * an object which has subtracted the x and y coordinates of another * object, needs to travel toward it. */ - int find_dir_2 (int x, int y) { @@ -2294,8 +2213,10 @@ { while (d < 1) d += 8; + while (d > 8) d -= 8; + return d; } @@ -2307,12 +2228,12 @@ int dirdiff (int dir1, int dir2) { - int - d; + int d; d = abs (dir1 - dir2); if (d > 4) d = 8 - d; + return d; } @@ -2325,9 +2246,7 @@ * Moved from spell_util.c to object.c with the other related direction * functions. */ - -int - reduction_dir[SIZEOFFREE][3] = { +int reduction_dir[SIZEOFFREE][3] = { {0, 0, 0}, /* 0 */ {0, 0, 0}, /* 1 */ {0, 0, 0}, /* 2 */ @@ -2487,7 +2406,6 @@ /* but it was simple to make and allows reusing the load_object function. */ /* Remember not to use load_object_str in a time-critical situation. */ /* Also remember that multiparts objects are not supported for now. */ - object * load_object_str (const char *obstr) { @@ -2527,13 +2445,11 @@ object * find_obj_by_type_subtype (const object *who, int type, int subtype) { - object *tmp; - - for (tmp = who->inv; tmp; tmp = tmp->below) + for (object *tmp = who->inv; tmp; tmp = tmp->below) if (tmp->type == type && tmp->subtype == subtype) return tmp; - return NULL; + return 0; } /* If ob has a field named key, return the link from the list, @@ -2545,13 +2461,11 @@ key_value * get_ob_key_link (const object *ob, const char *key) { - key_value *link; - - for (link = ob->key_values; link != NULL; link = link->next) + for (key_value *link = ob->key_values; link; link = link->next) if (link->key == key) return link; - return NULL; + return 0; } /* @@ -2601,8 +2515,7 @@ int set_ob_key_value_s (object *op, const shstr & canonical_key, const char *value, int add_key) { - key_value * - field = NULL, *last = NULL; + key_value *field = NULL, *last = NULL; for (field = op->key_values; field != NULL; field = field->next) { @@ -2640,9 +2553,8 @@ /* No field, we'll have to add it. */ if (!add_key) - { - return FALSE; - } + return FALSE; + /* There isn't any good reason to store a null * value in the key/value list. If the archetype has * this key, then we should also have it, so shouldn't