--- deliantra/server/common/map.C 2007/08/30 05:24:14 1.122 +++ deliantra/server/common/map.C 2008/08/17 22:46:26 1.146 @@ -1,11 +1,11 @@ /* - * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. + * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team + * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2001-2003,2007 Mark Wedel & Crossfire Development Team * Copyright (©) 1992,2007 Frank Tore Johansen * - * Crossfire TRT is free software: you can redistribute it and/or modify + * Deliantra 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 3 of the License, or * (at your option) any later version. @@ -18,16 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * The authors can be reached via e-mail to + * The authors can be reached via e-mail to */ #include #include "global.h" -#include "funcpoint.h" - #include "loader.h" - #include "path.h" /* This rolls up wall, blocks_magic, blocks_view, etc, all into @@ -168,11 +165,11 @@ } /* - * Returns true if the given object can't fit in the given spot. - * This is meant for multi space objects - for single space objecs, + * Returns qthe blocking object if the given object can't fit in the given + * spot. This is meant for multi space objects - for single space objecs, * just calling get_map_blocked and checking that against movement type - * of object. This function goes through all the parts of the - * multipart object and makes sure they can be inserted. + * of object. This function goes through all the parts of the multipart + * object and makes sure they can be inserted. * * While this doesn't call out of map, the get_map_flags does. * @@ -193,48 +190,33 @@ * code, we need to have actual object to check its move_type * against the move_block values. */ -int -ob_blocked (const object *ob, maptile *m, sint16 x, sint16 y) +bool +object::blocked (maptile *m, int x, int y) const { - archetype *tmp; - int flag; - maptile *m1; - sint16 sx, sy; - - if (!ob) + for (archetype *tmp = arch; tmp; tmp = (archetype *)tmp->more) { - flag = get_map_flags (m, &m1, x, y, &sx, &sy); - if (flag & P_OUT_OF_MAP) - return P_OUT_OF_MAP; - - /* don't have object, so don't know what types would block */ - return m1->at (sx, sy).move_block; - } + mapxy pos (m, x + tmp->x, y + tmp->y); - for (tmp = ob->arch; tmp; tmp = (archetype *)tmp->more) - { - flag = get_map_flags (m, &m1, x + tmp->x, y + tmp->y, &sx, &sy); + if (!pos.normalise ()) + return 1; - if (flag & P_OUT_OF_MAP) - return P_OUT_OF_MAP; - if (flag & P_IS_ALIVE) - return P_IS_ALIVE; + mapspace &ms = *pos; - mapspace &ms = m1->at (sx, sy); + if (ms.flags () & P_IS_ALIVE) + return 1; - /* find_first_free_spot() calls this function. However, often - * ob doesn't have any move type (when used to place exits) + /* However, often ob doesn't have any move type + * (signifying non-moving objects) * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work. */ - - if (ob->move_type == 0 && ms.move_block != MOVE_ALL) + if (!move_type && ms.move_block != MOVE_ALL) continue; /* Note it is intentional that we check ob - the movement type of the * head of the object should correspond for the entire object. */ - if (OB_TYPE_MOVE_BLOCK (ob, ms.move_block)) - return P_NO_PASS; + if (ms.blocks (move_type)) + return 1; } return 0; @@ -262,10 +244,9 @@ tmp = next; } - /* sum_weight will go through and calculate what all the containers are - * carrying. - */ - sum_weight (container); + // go through and calculate what all the containers are carrying. + //TODO: remove + container->update_weight (); } void @@ -279,6 +260,19 @@ tmp->flag [flag] = value; } +void +maptile::post_load_original () +{ + if (!spaces) + return; + + set_object_flag (FLAG_OBJ_ORIGINAL); + + for (mapspace *ms = spaces + size (); ms-- > spaces; ) + for (object *tmp = ms->bot; tmp; tmp = tmp->above) + INVOKE_OBJECT (RESET, tmp); +} + /* link_multipart_objects go through all the objects on the map looking * for objects whose arch says they are multipart yet according to the * info we have, they only have the head (as would be expected when @@ -324,17 +318,43 @@ { for (;;) { - coroapi::cede_to_tick_every (100); // cede once in a while + coroapi::cede_to_tick (); // cede once in a while switch (f.kw) { case KW_arch: if (object *op = object::read (f, this)) { + // TODO: why? if (op->inv) - sum_weight (op); + op->update_weight (); - insert_ob_in_map (op, this, op, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP | INS_MAP_LOAD); + if (IN_RANGE_EXC (op->x, 0, width) && IN_RANGE_EXC (op->y, 0, height)) + { + // we insert manually because + // a) its way faster + // b) we remove manually, too, and there are good reasons for that + // c) its correct + mapspace &ms = at (op->x, op->y); + + op->flag [FLAG_REMOVED] = false; + + op->above = 0; + op->below = ms.top; + + if (ms.top) + ms.top->above = op; + else + ms.bot = op; + + ms.top = op; + ms.flags_ = 0; + } + else + { + f.parse_warn (format ("object %s out of range", op->debug_desc ())); + op->destroy (); + } } continue; @@ -410,28 +430,6 @@ } bool -maptile::_load_objects (const char *path, bool skip_header) -{ - object_thawer f (path); - - if (!f) - return false; - - f.next (); - - if (skip_header) - for (;;) - { - keyword kw = f.kw; - f.skip (); - if (kw == KW_end) - break; - } - - return _load_objects (f); -} - -bool maptile::_save_objects (const char *path, int flags) { object_freezer freezer; @@ -613,8 +611,6 @@ { for (;;) { - thawer.next (); - switch (thawer.kw) { case KW_msg: @@ -658,6 +654,7 @@ case KW_per_player: thawer.get (per_player); break; case KW_per_party: thawer.get (per_party); break; case KW_no_reset: thawer.get (no_reset); break; + case KW_no_drop: thawer.get (no_drop); break; case KW_region: default_region = region::find (thawer.get_str ()); break; case KW_shopitems: shopitems = parse_shop_string (thawer.get_str ()); break; @@ -679,10 +676,11 @@ case KW_tile_path_4: thawer.get (tile_path [3]); break; case KW_ERROR: - set_key (thawer.kw_str, thawer.value); + set_key_text (thawer.kw_str, thawer.value); break; case KW_end: + thawer.next (); return true; default: @@ -690,22 +688,13 @@ return false; break; } + + thawer.next (); } abort (); } -bool -maptile::_load_header (const char *path) -{ - object_thawer thawer (path); - - if (!thawer) - return false; - - return _load_header (thawer); -} - /****************************************************************************** * This is the start of unique map handling code *****************************************************************************/ @@ -749,6 +738,7 @@ MAP_OUT (reset_timeout); MAP_OUT (fixed_resettime); MAP_OUT (no_reset); + MAP_OUT (no_drop); MAP_OUT (difficulty); if (default_region) MAP_OUT2 (region, default_region->name); @@ -812,24 +802,38 @@ void maptile::clear () { - sfree (regions, size ()); regions = 0; - delete [] regionmap; regionmap = 0; - if (spaces) { for (mapspace *ms = spaces + size (); ms-- > spaces; ) while (object *op = ms->bot) { - op = op->head_ (); - op->destroy_inv (false); - op->destroy (); + // manually remove, as to not trigger anything + if (ms->bot = op->above) + ms->bot->below = 0; + + op->flag [FLAG_REMOVED] = true; + + object *head = op->head_ (); + if (op == head) + { + op->destroy_inv (false); + op->destroy (); + } + else if (head->map != op->map) + { + LOG (llevDebug, "bad luck for object crossing map borders: %s", head->debug_desc ()); + head->destroy (); + } } - sfree (spaces, size ()), spaces = 0; + sfree0 (spaces, size ()); } if (buttons) free_objectlinkpt (buttons), buttons = 0; + + sfree0 (regions, size ()); + delete [] regionmap; regionmap = 0; } void @@ -992,10 +996,17 @@ { total_exp += op->stats.exp; - if (archetype *at = type_to_archetype (GENERATE_TYPE (op))) - total_exp += at->stats.exp * 8; + if (archetype *at = op->other_arch) + { + total_exp += at->stats.exp * 8; + monster_cnt++; + } - monster_cnt++; + for (object *inv = op->inv; inv; inv = inv->below) + { + total_exp += op->stats.exp * 8; + monster_cnt++; + } } } @@ -1044,6 +1055,7 @@ /* All clients need to get re-updated for the change */ update_all_map_los (this); + return 1; } @@ -1056,7 +1068,7 @@ void mapspace::update_ () { - object *tmp, *last = 0; + object *last = 0; uint8 flags = P_UPTODATE, light = 0, anywhere = 0; MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0; @@ -1068,15 +1080,14 @@ object *&middle = faces_obj[1] = 0; object *&floor = faces_obj[2] = 0; - for (tmp = bot; tmp; last = tmp, tmp = tmp->above) + for (object *tmp = bot; tmp; last = tmp, tmp = tmp->above) { /* This could be made additive I guess (two lights better than * one). But if so, it shouldn't be a simple additive - 2 * light bulbs do not illuminate twice as far as once since * it is a dissapation factor that is cubed. */ - if (tmp->glow_radius > light) - light = tmp->glow_radius; + light = max (light, tmp->glow_radius); /* This call is needed in order to update objects the player * is standing in that have animations (ie, grass, fire, etc). @@ -1105,6 +1116,7 @@ middle = tmp; anywhere = 1; } + /* Find the highest visible face around. If equal * visibilities, we still want the one nearer to the * top @@ -1163,7 +1175,7 @@ * 3) neither middle or top is set - need to set both. */ - for (tmp = last; tmp; tmp = tmp->below) + for (object *tmp = last; tmp; tmp = tmp->below) { /* Once we get to a floor, stop, since we already have a floor object */ if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) @@ -1231,7 +1243,7 @@ if (!tile_path[dir]) return 0; - if (tile_map[dir] && (!load || tile_map[dir]->in_memory == MAP_IN_MEMORY)) + if (tile_map[dir] && (!load || tile_map[dir]->in_memory == MAP_ACTIVE)) return 1; if ((tile_map[dir] = find_async (tile_path[dir], this, load))) @@ -1576,9 +1588,6 @@ object * maptile::insert (object *op, int x, int y, object *originator, int flags) { - if (!op->flag [FLAG_REMOVED]) - op->remove (); - return insert_ob_in_map_at (op, this, originator, flags, x, y); } @@ -1598,11 +1607,9 @@ } /* picks a random object from a style map. - * Redone by MSW so it should be faster and not use static - * variables to generate tables. */ object * -maptile::pick_random_object () const +maptile::pick_random_object (rand_gen &gen) const { /* while returning a null object will result in a crash, that * is actually preferable to an infinite loop. That is because @@ -1612,15 +1619,15 @@ */ for (int i = 1000; --i;) { - object *pick = at (rndm (width), rndm (height)).bot; + object *pick = at (gen (width), gen (height)).bot; // do not prefer big monsters just because they are big. - if (pick && pick->head_ () == pick) + if (pick && pick->is_head ()) return pick->head_ (); } // instead of crashing in the unlikely(?) case, try to return *something* - return get_archetype ("blocked"); + return archetype::find ("bug"); } void