/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
* Copyright (©) 2005,2006,2007,2008,2009,2010,2011 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2002-2005 Mark Wedel & Crossfire Development Team
* Copyright (©) 1992 Frank Tore Johansen
*
* Deliantra is free software: you can redistribute it and/or modify it under
* the terms of the Affero 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 Affero GNU General Public License
* and the GNU General Public License along with this program. If not, see
* .
*
* The authors can be reached via e-mail to
*/
/*
* The maptile is allocated each time a new map is opened.
* It contains pointers (very indirectly) to all objects on the map.
*/
#ifndef MAP_H
#define MAP_H
#include
//+GPL
#include "region.h"
#include "cfperl.h"
/* We set this size - this is to make magic map work properly on
* tiled maps. There is no requirement that this matches the
* tiled maps size - it just seemed like a reasonable value.
* Magic map code now always starts out putting the player in the
* center of the map - this makes the most sense when dealing
* with tiled maps.
* We also figure out the magicmap color to use as we process the
* spaces - this is more efficient as we already have up to date
* map pointers.
*/
#define MAGIC_MAP_SIZE 50
#define MAGIC_MAP_HALF MAGIC_MAP_SIZE/2
#define MAP_LAYERS 3
// tile map index
enum {
TILE_NORTH,
TILE_EAST,
TILE_SOUTH,
TILE_WEST,
TILE_UP,
TILE_DOWN,
TILE_NUM,
};
/* Values for state below */
enum {
MAP_SWAPPED, // header loaded, nothing else
MAP_INACTIVE, // in memory, linkable, but not active
MAP_ACTIVE, // running!
};
/* GET_MAP_FLAGS really shouldn't be used very often - get_map_flags should
* really be used, as it is multi tile aware. However, there are some cases
* where it is known the map is not tiled or the values are known
* consistent (eg, op->map, op->x, op->y)
*/
// all those macros are herewith declared legacy
#define GET_MAP_FLAGS(M,X,Y) (M)->at((X),(Y)).flags ()
#define GET_MAP_OB(M,X,Y) (M)->at((X),(Y)).bot
#define GET_MAP_TOP(M,X,Y) (M)->at((X),(Y)).top
#define GET_MAP_FACE_OBJ(M,X,Y,L) (M)->at((X),(Y)).faces_obj[L]
#define GET_MAP_MOVE_BLOCK(M,X,Y) (M)->at((X),(Y)).move_block
#define GET_MAP_MOVE_SLOW(M,X,Y) (M)->at((X),(Y)).move_slow
#define GET_MAP_MOVE_ON(M,X,Y) (M)->at((X),(Y)).move_on
#define GET_MAP_MOVE_OFF(M,X,Y) (M)->at((X),(Y)).move_off
/* You should really know what you are doing before using this - you
* should almost always be using out_of_map instead, which takes into account
* map tiling.
*/
#define OUT_OF_REAL_MAP(M,X,Y) (!(IN_RANGE_EXC ((X), 0, (M)->width) && IN_RANGE_EXC ((Y), 0, (M)->height)))
/* These are used in the MapLook flags element. They are not used in
* in the object flags structure.
*/
#define P_BLOCKSVIEW 0x01
#define P_NO_MAGIC 0x02 /* Spells (some) can't pass this object */
#define P_NO_CLERIC 0x04 /* no clerical spells cast here */
#define P_SAFE 0x08 /* If this is set the map tile is a safe space,
* that means, nothing harmful can be done,
* such as: bombs, potion usage, alchemy, spells
* this was introduced to make shops safer
* but is useful in other situations */
#define P_PLAYER 0x10 /* a player (or something seeing these objects) is on this mapspace */
#define P_IS_ALIVE 0x20 /* something alive is on this space */
#define P_UPTODATE 0x80 // this space is up to date
/* The following two values are not stored in the MapLook flags, but instead
* used in the get_map_flags value - that function is used to return
* the flag value, as well as other conditions - using a more general
* function that does more of the work can hopefully be used to replace
* lots of duplicate checks currently in the code.
*/
#define P_OUT_OF_MAP 0x10000 /* This space is outside the map */
#define P_NEW_MAP 0x20000 /* Coordinates passed result in a new tiled map */
/* Instead of having numerous arrays that have information on a
* particular space (was map, floor, floor2, map_ob),
* have this structure take care of that information.
* This puts it all in one place, and should also make it easier
* to extend information about a space.
*/
INTERFACE_CLASS (mapspace)
struct mapspace
{
object *ACC (RW, bot);
object *ACC (RW, top); /* lowest/highest object on this space */
object *ACC (RW, faces_obj[MAP_LAYERS]);/* face objects for the 3 layers */
uint8 flags_; /* flags about this space (see the P_ values above) */
sint8 ACC (RW, light); /* How much light this space provides */
MoveType ACC (RW, move_block); /* What movement types this space blocks */
MoveType ACC (RW, move_slow); /* What movement types this space slows */
MoveType ACC (RW, move_on); /* What movement types are activated */
MoveType ACC (RW, move_off); /* What movement types are activated */
uint16_t ACC (RW, items_); // saturates at 64k
uint32_t ACC (RW, volume_); // ~dm³ (not cm³) (factor is actually 1024)
uint32_t ACC (RW, smell); // the last count a player was seen here, or 0
static uint32_t ACC (RW, smellcount); // global smell counter
uint32_t pad1_; // pad to 64 bytes on 64 bit systems
//-GPL
void update_ ();
MTH void update ()
{
// we take advantage of the fact that 0x80 is the sign bit
// to generate more efficient code on many cpus
assert (sint8 (P_UPTODATE) < 0);
assert (sint8 (-1 & ~P_UPTODATE) >= 0);
if (expect_false (sint8 (flags_) >= 0))
update_ ();
// must be true by now (gcc seems content with only the second test)
assume (sint8 (flags_) < 0);
assume (flags_ & P_UPTODATE);
}
MTH uint8 flags ()
{
update ();
return flags_;
}
MTH void invalidate ()
{
flags_ = 0;
}
MTH object *player ()
{
object *op;
if (flags () & P_PLAYER)
for (op = top; op->type != PLAYER; op = op->below)
;
else
op = 0;
return op;
}
MTH uint32 items()
{
update ();
return items_;
}
// return the item volume on this mapspace in cm³
MTH uint64 volume ()
{
update ();
return volume_ * 1024;
}
bool blocks (MoveType mt) const
{
return move_block && (mt & move_block) == mt;
}
bool blocks (object *op) const
{
return blocks (op->move_type);
}
};
// a rectangular area of a map, used my split_to_tiles/unordered_mapwalk
struct maprect
{
maptile *m;
int x0, y0;
int x1, y1;
int dx, dy; // offset to go from local coordinates to original tile */
};
// (refcounted) list of objects on this map that need physics processing
struct physics_queue
: unordered_vector