--- deliantra/server/common/map.C 2007/01/04 16:19:31 1.68
+++ deliantra/server/common/map.C 2007/07/13 15:54:40 1.113
@@ -1,31 +1,32 @@
/*
- CrossFire, A Multiplayer game for X-windows
-
- Copyright (C) 2001-2003 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.
+ * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
+ *
+ * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT 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
+ * 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.
+ *
+ * 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, see .
+ *
+ * The authors can be reached via e-mail to
+ */
- The authors can be reached via e-mail at
-*/
+#include
-#include
-#include
+#include "global.h"
+#include "funcpoint.h"
-#include
-#include
+#include "loader.h"
#include "path.h"
@@ -68,9 +69,9 @@
int mode = 0;
if (prepend_dir)
- strcpy (buf, create_pathname (name));
+ assign (buf, create_pathname (name));
else
- strcpy (buf, name);
+ assign (buf, name);
/* old method (strchr(buf, '\0')) seemd very odd to me -
* this method should be equivalant and is clearer.
@@ -174,8 +175,7 @@
if (!(mflags & P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK (ob, blocked))
return 0;
- if (ob->head != NULL)
- ob = ob->head;
+ ob = ob->head_ ();
/* We basically go through the stack of objects, and if there is
* some other object that has NO_PASS or FLAG_ALIVE set, return
@@ -215,13 +215,17 @@
/* Broke apart a big nasty if into several here to make
* this more readable. first check - if the space blocks
* movement, can't move here.
- * second - if a monster, can't move there, unles it is a
+ * second - if a monster, can't move there, unless it is a
* hidden dm
*/
if (OB_MOVE_BLOCK (ob, tmp))
return 1;
- if (QUERY_FLAG (tmp, FLAG_ALIVE) && tmp->head != ob && tmp != ob &&
- tmp->type != DOOR && !(QUERY_FLAG (tmp, FLAG_WIZ) && tmp->contr->hidden))
+
+ if (tmp->flag [FLAG_ALIVE]
+ && tmp->head_ () != ob
+ && tmp != ob
+ && tmp->type != DOOR
+ && !(tmp->flag [FLAG_WIZ] && tmp->contr->hidden))
return 1;
}
@@ -229,7 +233,6 @@
return 0;
}
-
/*
* Returns true if the given object can't fit in the given spot.
* This is meant for multi space objects - for single space objecs,
@@ -274,9 +277,9 @@
return m1->at (sx, sy).move_block;
}
- for (tmp = ob->arch; tmp; tmp = tmp->more)
+ for (tmp = ob->arch; tmp; tmp = (archetype *)tmp->more)
{
- flag = get_map_flags (m, &m1, x + tmp->clone.x, y + tmp->clone.y, &sx, &sy);
+ flag = get_map_flags (m, &m1, x + tmp->x, y + tmp->y, &sx, &sy);
if (flag & P_OUT_OF_MAP)
return P_OUT_OF_MAP;
@@ -345,8 +348,7 @@
/* 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
- * they are saved). We do have to look for the old maps that did save
- * the more sections and not re-add sections for them.
+ * they are saved).
*/
void
maptile::link_multipart_objects ()
@@ -355,162 +357,107 @@
return;
for (mapspace *ms = spaces + size (); ms-- > spaces; )
- for (object *tmp = ms->bot; tmp; )
- {
- object *above = tmp->above;
-
- /* already multipart - don't do anything more */
- if (!tmp->head && !tmp->more)
- {
- /* If there is nothing more to this object, this for loop
- * won't do anything.
- */
- archetype *at;
- object *last, *op;
- for (at = tmp->arch->more, last = tmp;
- at;
- at = at->more, last = op)
- {
- op = arch_to_object (at);
+ {
+ object *op = ms->bot;
+ while (op)
+ {
+ /* already multipart - don't do anything more */
+ if (op->head_ () == op && !op->more && op->arch->more)
+ {
+ op->remove ();
+ op->expand_tail ();
- /* update x,y coordinates */
- op->x += tmp->x;
- op->y += tmp->y;
- op->head = tmp;
- op->map = this;
- last->more = op;
- op->name = tmp->name;
- op->title = tmp->title;
-
- /* we could link all the parts onto tmp, and then just
- * call insert_ob_in_map once, but the effect is the same,
- * as insert_ob_in_map will call itself with each part, and
- * the coding is simpler to just to it here with each part.
- */
- insert_ob_in_map (op, op->map, tmp, INS_NO_MERGE | INS_ABOVE_FLOOR_ONLY | INS_NO_WALK_ON);
- }
- }
+ // FIXME: INS_ON_TOP is just a workaround for the pentagram vs.
+ // multi-tile monster bug, where INS_ABOVE_FLOOR_ONLY put the monsters
+ // below the pentagrams... hopefully INS_ON_TOP doesn't break anything
+ insert (op, op->x, op->y, 0, INS_NO_MERGE | INS_ON_TOP | INS_NO_WALK_ON);
- tmp = above;
- }
+ op = ms->bot; // we are mutating the mapspace too much with INS_ON_TOP
+ // so we have to reset the iteration through the mapspace
+ }
+ else
+ op = op->above;
+ }
+ }
}
/*
* Loads (ands parses) the objects into a given map from the specified
* file pointer.
- * mapflags is the same as we get with load_original_map
*/
bool
-maptile::load_objects (object_thawer &thawer)
+maptile::_load_objects (object_thawer &f)
{
- int unique;
- object *op, *prev = NULL, *last_more = NULL, *otmp;
-
- op = object::create ();
- op->map = this; /* To handle buttons correctly */
-
- while (int i = load_object (thawer, op, 0))
+ for (;;)
{
- /* if the archetype for the object is null, means that we
- * got an invalid object. Don't do anything with it - the game
- * or editor will not be able to do anything with it either.
- */
- if (op->arch == NULL)
- {
- LOG (llevDebug, "Discarding object without arch: %s\n", op->name ? (const char *) op->name : "(null)");
- continue;
- }
+ coroapi::cede_to_tick_every (100); // cede once in a while
- switch (i)
+ switch (f.kw)
{
- case LL_NORMAL:
- insert_ob_in_map (op, this, op, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP | INS_MAP_LOAD);
+ case KW_arch:
+ if (object *op = object::read (f, this))
+ {
+ if (op->inv)
+ sum_weight (op);
- if (op->inv)
- sum_weight (op);
+ insert_ob_in_map (op, this, op, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP | INS_MAP_LOAD);
+ }
- prev = op, last_more = op;
- break;
+ continue;
+
+ case KW_EOF:
+ return true;
- case LL_MORE:
- insert_ob_in_map (op, this, op, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
- op->head = prev, last_more->more = op, last_more = op;
+ default:
+ if (!f.parse_error ("map file"))
+ return false;
break;
}
- op = object::create ();
- op->map = this;
+ f.next ();
}
- op->destroy ();
-
-#if 0
- for (i = 0; i < width; i++)
- for (j = 0; j < height; j++)
- {
- unique = 0;
- /* check for unique items, or unique squares */
- for (otmp = GET_MAP_OB (m, i, j); otmp; otmp = otmp->above)
- {
- if (QUERY_FLAG (otmp, FLAG_UNIQUE) || QUERY_FLAG (otmp, FLAG_OBJ_SAVE_ON_OVL))
- unique = 1;
-
- if (!(mapflags & (MAP_OVERLAY | MAP_PLAYER_UNIQUE) || unique))
- SET_FLAG (otmp, FLAG_OBJ_ORIGINAL);
- }
- }
-#endif
-
return true;
}
void
maptile::activate ()
{
- if (!spaces)
- return;
+ active = true;
- for (mapspace *ms = spaces + size (); ms-- > spaces; )
- for (object *op = ms->bot; op; op = op->above)
- op->activate_recursive ();
+ if (spaces)
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ for (object *op = ms->bot; op; op = op->above)
+ op->activate_recursive ();
}
void
maptile::deactivate ()
{
- if (!spaces)
- return;
+ active = false;
- for (mapspace *ms = spaces + size (); ms-- > spaces; )
- for (object *op = ms->bot; op; op = op->above)
- op->deactivate_recursive ();
+ if (spaces)
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ for (object *op = ms->bot; op; op = op->above)
+ op->deactivate_recursive ();
}
bool
-maptile::save_objects (object_freezer &freezer, int flags)
+maptile::_save_objects (object_freezer &f, int flags)
{
- static int cede_count = 0;
+ coroapi::cede_to_tick ();
if (flags & IO_HEADER)
- save_header (freezer);
+ _save_header (f);
if (!spaces)
return false;
for (int i = 0; i < size (); ++i)
{
- if (cede_count >= 500)
- {
- cede_count = 0;
- coroapi::cede ();
- }
-
int unique = 0;
for (object *op = spaces [i].bot; op; op = op->above)
{
- // count per-object, but cede only when modification-safe
- cede_count++;
-
if (op->flag [FLAG_UNIQUE] && op->flag [FLAG_IS_FLOOR])
unique = 1;
@@ -520,44 +467,46 @@
if (unique || op->flag [FLAG_UNIQUE])
{
if (flags & IO_UNIQUES)
- save_object (freezer, op, 1);
+ op->write (f);
}
else if (flags & IO_OBJECTS)
- save_object (freezer, op, 1);
+ op->write (f);
}
}
+ coroapi::cede_to_tick ();
+
return true;
}
bool
-maptile::load_objects (const char *path, bool skip_header)
+maptile::_load_objects (const char *path, bool skip_header)
{
- object_thawer thawer (path);
+ object_thawer f (path);
- if (!thawer)
+ if (!f)
return false;
+ f.next ();
+
if (skip_header)
for (;;)
{
- keyword kw = thawer.get_kv ();
-
+ keyword kw = f.kw;
+ f.skip ();
if (kw == KW_end)
break;
-
- thawer.skip_kv (kw);
}
- return load_objects (thawer);
+ return _load_objects (f);
}
bool
-maptile::save_objects (const char *path, int flags)
+maptile::_save_objects (const char *path, int flags)
{
object_freezer freezer;
- if (!save_objects (freezer, flags))
+ if (!_save_objects (freezer, flags))
return false;
return freezer.save (path);
@@ -568,14 +517,13 @@
in_memory = MAP_SWAPPED;
/* The maps used to pick up default x and y values from the
- * map archetype. Mimic that behaviour.
+ * map archetype. Mimic that behaviour.
*/
- width = 16;
- height = 16;
- reset_timeout = 0;
- timeout = 300;
- enter_x = 0;
- enter_y = 0;
+ width = 16;
+ height = 16;
+ timeout = 300;
+ max_nrof = 1000; // 1000 items of anything
+ max_volume = 2000000; // 2m³
}
maptile::maptile (int w, int h)
@@ -731,25 +679,14 @@
* MSW 2001-07-01
*/
bool
-maptile::load_header (object_thawer &thawer)
+maptile::_load_header (object_thawer &thawer)
{
- char buf[HUGE_BUF], msgbuf[HUGE_BUF], maplorebuf[HUGE_BUF], *key = NULL, *value, *end;
- int msgpos = 0;
- int maplorepos = 0;
-
for (;;)
{
- keyword kw = thawer.get_kv ();
+ thawer.next ();
- switch (kw)
+ switch (thawer.kw)
{
- case KW_EOF:
- LOG (llevError, "%s: end of file while reading map header, aborting header load.\n", &path);
- return false;
-
- case KW_end:
- return true;
-
case KW_msg:
thawer.get_ml (KW_endmsg, msg);
break;
@@ -790,8 +727,9 @@
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_region: get_region_by_name (thawer.get_str ()); break;
+ case KW_region: default_region = region::find (thawer.get_str ()); break;
case KW_shopitems: shopitems = parse_shop_string (thawer.get_str ()); break;
// old names new names
@@ -810,8 +748,16 @@
case KW_tile_path_3: thawer.get (tile_path [2]); break;
case KW_tile_path_4: thawer.get (tile_path [3]); break;
+ case KW_ERROR:
+ set_key (thawer.kw_str, thawer.value);
+ break;
+
+ case KW_end:
+ return true;
+
default:
- LOG (llevError, "%s: skipping unknown key in map header: %s\n", &path, keyword_str [kw]);
+ if (!thawer.parse_error ("map", 0))
+ return false;
break;
}
}
@@ -820,14 +766,14 @@
}
bool
-maptile::load_header (const char *path)
+maptile::_load_header (const char *path)
{
object_thawer thawer (path);
if (!thawer)
return false;
- return load_header (thawer);
+ return _load_header (thawer);
}
/******************************************************************************
@@ -848,7 +794,7 @@
if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
unique = 1;
- if (op->head == NULL && (QUERY_FLAG (op, FLAG_UNIQUE) || unique))
+ if (op->head_ () == op && (QUERY_FLAG (op, FLAG_UNIQUE) || unique))
{
op->destroy_inv (false);
op->destroy ();
@@ -860,7 +806,7 @@
}
bool
-maptile::save_header (object_freezer &freezer)
+maptile::_save_header (object_freezer &freezer)
{
#define MAP_OUT(k) freezer.put (KW_ ## k, k)
#define MAP_OUT2(k,v) freezer.put (KW_ ## k, v)
@@ -872,9 +818,10 @@
MAP_OUT (reset_time);
MAP_OUT (reset_timeout);
MAP_OUT (fixed_resettime);
+ MAP_OUT (no_reset);
MAP_OUT (difficulty);
- if (region) MAP_OUT2 (region, region->name);
+ if (default_region) MAP_OUT2 (region, default_region->name);
if (shopitems)
{
@@ -919,11 +866,11 @@
}
bool
-maptile::save_header (const char *path)
+maptile::_save_header (const char *path)
{
object_freezer freezer;
- if (!save_header (freezer))
+ if (!_save_header (freezer))
return false;
return freezer.save (path);
@@ -935,20 +882,21 @@
void
maptile::clear ()
{
- if (!spaces)
- return;
-
- for (mapspace *ms = spaces + size (); ms-- > spaces; )
- while (object *op = ms->bot)
- {
- if (op->head)
- op = op->head;
+ sfree (regions, size ()); regions = 0;
+ delete [] regionmap; regionmap = 0;
- op->destroy_inv (false);
- op->destroy ();
- }
+ if (spaces)
+ {
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ while (object *op = ms->bot)
+ {
+ op = op->head_ ();
+ op->destroy_inv (false);
+ op->destroy ();
+ }
- sfree (spaces, size ()), spaces = 0;
+ sfree (spaces, size ()), spaces = 0;
+ }
if (buttons)
free_objectlinkpt (buttons), buttons = 0;
@@ -993,6 +941,74 @@
clear ();
}
+/* decay and destroy perishable items in a map */
+void
+maptile::do_decay_objects ()
+{
+ if (!spaces)
+ return;
+
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ for (object *above, *op = ms->bot; op; op = above)
+ {
+ above = op->above;
+
+ bool destroy = 0;
+
+ // do not decay anything above unique floor tiles (yet :)
+ if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
+ break;
+
+ if (QUERY_FLAG (op, FLAG_IS_FLOOR)
+ || QUERY_FLAG (op, FLAG_OBJ_ORIGINAL)
+ || QUERY_FLAG (op, FLAG_OBJ_SAVE_ON_OVL)
+ || QUERY_FLAG (op, FLAG_UNIQUE)
+ || QUERY_FLAG (op, FLAG_OVERLAY_FLOOR)
+ || QUERY_FLAG (op, FLAG_UNPAID)
+ || op->is_alive ())
+ ; // do not decay
+ else if (op->is_weapon ())
+ {
+ op->stats.dam--;
+ if (op->stats.dam < 0)
+ destroy = 1;
+ }
+ else if (op->is_armor ())
+ {
+ op->stats.ac--;
+ if (op->stats.ac < 0)
+ destroy = 1;
+ }
+ else if (op->type == FOOD)
+ {
+ op->stats.food -= rndm (5, 20);
+ if (op->stats.food < 0)
+ destroy = 1;
+ }
+ else
+ {
+ int mat = op->materials;
+
+ if (mat & M_PAPER
+ || mat & M_LEATHER
+ || mat & M_WOOD
+ || mat & M_ORGANIC
+ || mat & M_CLOTH
+ || mat & M_LIQUID
+ || (mat & M_IRON && rndm (1, 5) == 1)
+ || (mat & M_GLASS && rndm (1, 2) == 1)
+ || ((mat & M_STONE || mat & M_ADAMANT) && rndm (1, 10) == 1)
+ || ((mat & M_SOFT_METAL || mat & M_BONE) && rndm (1, 3) == 1)
+ || (mat & M_ICE && temp > 32))
+ destroy = 1;
+ }
+
+ /* adjust overall chance below */
+ if (destroy && rndm (0, 1))
+ op->destroy ();
+ }
+}
+
/*
* Updates every button on the map (by calling update_button() for them).
*/
@@ -1048,7 +1064,7 @@
total_exp += op->stats.exp;
if (archetype *at = type_to_archetype (GENERATE_TYPE (op)))
- total_exp += at->clone.stats.exp * 8;
+ total_exp += at->stats.exp * 8;
monster_cnt++;
}
@@ -1112,18 +1128,16 @@
mapspace::update_ ()
{
object *tmp, *last = 0;
- uint8 flags = 0, light = 0, anywhere = 0;
- New_Face *top, *floor, *middle;
- object *top_obj, *floor_obj, *middle_obj;
+ uint8 flags = P_UPTODATE, light = 0, anywhere = 0;
MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
- middle = blank_face;
- top = blank_face;
- floor = blank_face;
-
- middle_obj = 0;
- top_obj = 0;
- floor_obj = 0;
+ //object *middle = 0;
+ //object *top = 0;
+ //object *floor = 0;
+ // this seems to generate better code than using locals, above
+ object *&top = faces_obj[0] = 0;
+ object *&middle = faces_obj[1] = 0;
+ object *&floor = faces_obj[2] = 0;
for (tmp = bot; tmp; last = tmp, tmp = tmp->above)
{
@@ -1146,37 +1160,28 @@
if (!tmp->invisible)
{
if ((tmp->type == PLAYER || QUERY_FLAG (tmp, FLAG_MONSTER)))
- {
- top = tmp->face;
- top_obj = tmp;
- }
+ top = tmp;
else if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
{
/* If we got a floor, that means middle and top were below it,
* so should not be visible, so we clear them.
*/
- middle = blank_face;
- top = blank_face;
- floor = tmp->face;
- floor_obj = tmp;
+ middle = 0;
+ top = 0;
+ floor = tmp;
}
/* Flag anywhere have high priority */
else if (QUERY_FLAG (tmp, FLAG_SEE_ANYWHERE))
{
- middle = tmp->face;
-
- middle_obj = tmp;
+ middle = tmp;
anywhere = 1;
}
/* Find the highest visible face around. If equal
* visibilities, we still want the one nearer to the
* top
*/
- else if (middle == blank_face || (tmp->face->visibility > middle->visibility && !anywhere))
- {
- middle = tmp->face;
- middle_obj = tmp;
- }
+ else if (!middle || (::faces [tmp->face].visibility > ::faces [middle->face].visibility && !anywhere))
+ middle = tmp;
}
if (tmp == tmp->above)
@@ -1221,7 +1226,7 @@
* may be possible for the faces to match but be different objects.
*/
if (top == middle)
- middle = blank_face;
+ middle = 0;
/* There are three posibilities at this point:
* 1) top face is set, need middle to be set.
@@ -1236,19 +1241,18 @@
break;
/* If two top faces are already set, quit processing */
- if ((top != blank_face) && (middle != blank_face))
+ if (top && middle)
break;
/* Only show visible faces */
if (!tmp->invisible)
{
/* Fill in top if needed */
- if (top == blank_face)
+ if (!top)
{
- top = tmp->face;
- top_obj = tmp;
+ top = tmp;
if (top == middle)
- middle = blank_face;
+ middle = 0;
}
else
{
@@ -1259,10 +1263,9 @@
* more to fill in. We don't check visiblity here, since
*
*/
- if (tmp->face != top)
+ if (tmp != top)
{
- middle = tmp->face;
- middle_obj = tmp;
+ middle = tmp;
break;
}
}
@@ -1270,14 +1273,27 @@
}
if (middle == floor)
- middle = blank_face;
+ middle = 0;
if (top == middle)
- middle = blank_face;
+ middle = 0;
+
+#if 0
+ faces_obj [0] = top;
+ faces_obj [1] = middle;
+ faces_obj [2] = floor;
+#endif
+}
+
+uint64
+mapspace::volume () const
+{
+ uint64 vol = 0;
- faces [0] = top; faces_obj [0] = top != blank_face ? top_obj : 0;
- faces [1] = middle; faces_obj [1] = middle != blank_face ? middle_obj : 0;
- faces [2] = floor; faces_obj [2] = floor != blank_face ? floor_obj : 0;
+ for (object *op = top; op && !op->flag [FLAG_NO_PICK]; op = op->below)
+ vol += op->volume ();
+
+ return vol;
}
/* this updates the orig_map->tile_map[tile_num] value after finding
@@ -1288,21 +1304,26 @@
static inline maptile *
find_and_link (maptile *orig_map, int tile_num)
{
- maptile *mp = orig_map->find_sync (orig_map->tile_path [tile_num], orig_map);
+ maptile *mp = orig_map->tile_map [tile_num];
if (!mp)
{
- // emergency mode, manufacture a dummy map, this creates a memleak, but thats fine
- LOG (llevError, "FATAL: cannot load tiled map %s from %s, leaking memory and worse!\n",
- &orig_map->tile_path[tile_num], &orig_map->path);
- mp = new maptile (1, 1);
- mp->alloc ();
- mp->in_memory = MAP_IN_MEMORY;
+ mp = orig_map->find_sync (orig_map->tile_path [tile_num], orig_map);
+
+ if (!mp)
+ {
+ // emergency mode, manufacture a dummy map, this creates a memleak, but thats fine
+ LOG (llevError, "FATAL: cannot load tiled map %s from %s, leaking memory and worse!\n",
+ &orig_map->tile_path[tile_num], &orig_map->path);
+ mp = new maptile (1, 1);
+ mp->alloc ();
+ mp->in_memory = MAP_IN_MEMORY;
+ }
}
int dest_tile = (tile_num + 2) % 4;
- orig_map->tile_map[tile_num] = mp;
+ orig_map->tile_map [tile_num] = mp;
// optimisation: back-link map to origin map if euclidean
//TODO: non-euclidean maps MUST GO
@@ -1447,7 +1468,7 @@
* Return whether map2 is adjacent to map1. If so, store the distance from
* map1 to map2 in dx/dy.
*/
-static int
+int
adjacent_map (const maptile *map1, const maptile *map2, int *dx, int *dy)
{
if (!map1 || !map2)
@@ -1548,7 +1569,7 @@
* creature is. get_rangevector takes into account map tiling,
* so you just can not look the the map coordinates and get the
* righte value. distance_x/y are distance away, which
- * can be negativbe. direction is the crossfire direction scheme
+ * can be negative. direction is the crossfire direction scheme
* that the creature should head. part is the part of the
* monster that is closest.
*
@@ -1569,9 +1590,9 @@
if (!adjacent_map (op1->map, op2->map, &retval->distance_x, &retval->distance_y))
{
/* be conservative and fill in _some_ data */
- retval->distance = 100000;
- retval->distance_x = 32767;
- retval->distance_y = 32767;
+ retval->distance = 10000;
+ retval->distance_x = 10000;
+ retval->distance_y = 10000;
retval->direction = 0;
retval->part = 0;
}
@@ -1586,7 +1607,6 @@
/* If this is multipart, find the closest part now */
if (!(flags & 0x1) && op1->more)
{
- object *tmp;
int best_distance = retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y, tmpi;
/* we just take the offset of the piece to head to figure
@@ -1595,7 +1615,7 @@
* same axis as is used for multipart objects, the simply arithmetic
* below works.
*/
- for (tmp = op1->more; tmp != NULL; tmp = tmp->more)
+ for (object *tmp = op1->more; tmp; tmp = tmp->more)
{
tmpi = (op1->x - tmp->x + retval->distance_x) * (op1->x - tmp->x + retval->distance_x) +
(op1->y - tmp->y + retval->distance_y) * (op1->y - tmp->y + retval->distance_y);
@@ -1605,14 +1625,16 @@
best = tmp;
}
}
+
if (best != op1)
{
retval->distance_x += op1->x - best->x;
retval->distance_y += op1->y - best->y;
}
}
+
retval->part = best;
- retval->distance = isqrt (retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y);
+ retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
}
}
@@ -1627,9 +1649,8 @@
* for something in the future. Also, since no object is pasted, the best
* field of the rv_vector is set to NULL.
*/
-
void
-get_rangevector_from_mapcoord (const maptile *m, int x, int y, const object *op2, rv_vector * retval, int flags)
+get_rangevector_from_mapcoord (const maptile *m, int x, int y, const object *op2, rv_vector *retval, int flags)
{
if (!adjacent_map (m, op2->map, &retval->distance_x, &retval->distance_y))
{
@@ -1646,7 +1667,7 @@
retval->distance_y += op2->y - y;
retval->part = NULL;
- retval->distance = isqrt (retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y);
+ retval->distance = idistance (retval->distance_x, retval->distance_y);
retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
}
}
@@ -1676,3 +1697,44 @@
return insert_ob_in_map_at (op, this, originator, flags, x, y);
}
+region *
+maptile::region (int x, int y) const
+{
+ if (regions
+ && regionmap
+ && !OUT_OF_REAL_MAP (this, x, y))
+ if (struct region *reg = regionmap [regions [y * width + x]])
+ return reg;
+
+ if (default_region)
+ return default_region;
+
+ return ::region::default_region ();
+}
+
+/* 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
+{
+ /* while returning a null object will result in a crash, that
+ * is actually preferable to an infinite loop. That is because
+ * most servers will automatically restart in case of crash.
+ * Change the logic on getting the random space - shouldn't make
+ * any difference, but this seems clearer to me.
+ */
+ for (int i = 1000; --i;)
+ {
+ object *pick = at (rndm (width), rndm (height)).bot;
+
+ // do not prefer big monsters just because they are big.
+ if (pick && pick->head_ () == pick)
+ return pick->head_ ();
+ }
+
+ // instead of crashing in the unlikely(?) case, try to return *something*
+ return get_archetype ("blocked");
+}
+