3916 lines
90 KiB
C++
3916 lines
90 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||
// Copyright (C) 2010 Winch Gate Property Limited
|
||
//
|
||
// This program is free software: you can redistribute it and/or modify
|
||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Affero General Public License
|
||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
|
||
|
||
#ifndef NL_WORLD_MAP_H
|
||
#define NL_WORLD_MAP_H
|
||
|
||
#include "nel/misc/types_nl.h"
|
||
#include "nel/misc/time_nl.h"
|
||
#include "nel/misc/debug.h"
|
||
#include "nel/misc/stream.h"
|
||
|
||
#include "nel/pacs/u_global_position.h"
|
||
#include "nel/misc/vectord.h"
|
||
|
||
#include "16x16_layer.h"
|
||
|
||
#include "ai_coord.h"
|
||
#include "ai_vector.h"
|
||
#include "ai_types.h"
|
||
|
||
class CFollowPath;
|
||
|
||
namespace RYPACSCRUNCH
|
||
{
|
||
|
||
class CPacsCruncher;
|
||
|
||
}
|
||
|
||
namespace RYAI_MAP_CRUNCH
|
||
{
|
||
|
||
enum TAStarFlag
|
||
{
|
||
Nothing = 0,
|
||
Interior = 1,
|
||
Water = 2,
|
||
NoGo = 4,
|
||
WaterAndNogo = 6,
|
||
GroundFlags = WaterAndNogo
|
||
};
|
||
|
||
const std::string& toString(TAStarFlag flag);
|
||
TAStarFlag toAStarFlag(const std::string& str);
|
||
|
||
uint const WorldMapGridSize = 256;
|
||
double const WorldGridResolution = 1.;
|
||
NLMISC::CVectorD const WorldStartOffset = NLMISC::CVectorD(0., 0., 0.);
|
||
|
||
typedef sint TLevel;
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* Slot for the 3 map layer (corresponding to 3 heights of deplacement)
|
||
* \author Stephane le Dorze
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CSlot
|
||
{
|
||
public:
|
||
enum
|
||
{
|
||
INVALID_SLOT = 3
|
||
};
|
||
|
||
public:
|
||
explicit CSlot();
|
||
explicit CSlot(uint slot);
|
||
|
||
bool isValid() const { return _Slot!=INVALID_SLOT; }
|
||
void setSlot(CSlot const& slot) { _Slot = slot._Slot; }
|
||
|
||
bool operator ==(CSlot const& slot) const { return _Slot==slot._Slot; }
|
||
bool operator !=(CSlot const& slot) const { return _Slot!=slot._Slot; }
|
||
|
||
bool operator >(CSlot const& slot) const { return _Slot>slot._Slot; }
|
||
bool operator <(CSlot const& slot) const { return _Slot<slot._Slot; }
|
||
|
||
bool operator >=(CSlot const& slot) const { return _Slot>=slot._Slot; }
|
||
bool operator <=(CSlot const& slot) const { return _Slot<=slot._Slot; }
|
||
|
||
CSlot const& operator ++();
|
||
|
||
uint8 slot() const { return _Slot; }
|
||
|
||
private:
|
||
uint8 _Slot;
|
||
};
|
||
|
||
inline
|
||
CSlot::CSlot()
|
||
: _Slot(INVALID_SLOT)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CSlot::CSlot(uint slot)
|
||
: _Slot(slot)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(slot>=0 && slot<=3);
|
||
#endif
|
||
}
|
||
|
||
inline
|
||
CSlot const& CSlot::operator ++()
|
||
{
|
||
++_Slot;
|
||
#ifdef NL_DEBUG
|
||
nlassert(_Slot<=INVALID_SLOT);
|
||
#endif
|
||
return *this;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* Compressed link set for the 4 cardinal directions
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CCellLinkage
|
||
// passer les param<61>tres de CCellLinkage en r<>f<EFBFBD>rences. (quand meme) et enlever les tests de validit<69>. (grosse mise <20> jour en perspective).
|
||
{
|
||
public:
|
||
enum
|
||
{
|
||
SouthSlotOffset = 0,
|
||
SouthSlotMask = 0x03,
|
||
EastSlotOffset = 2,
|
||
EastSlotMask = 0x0c,
|
||
NorthSlotOffset = 4,
|
||
NorthSlotMask = 0x30,
|
||
WestSlotOffset = 6,
|
||
WestSlotMask = 0xc0,
|
||
};
|
||
|
||
public:
|
||
CCellLinkage(uint8 links = 0xff);
|
||
|
||
CSlot SSlot() const { return CSlot((_Links & SouthSlotMask) >> SouthSlotOffset); }
|
||
CSlot ESlot() const { return CSlot((_Links & EastSlotMask) >> EastSlotOffset); }
|
||
CSlot NSlot() const { return CSlot((_Links & NorthSlotMask) >> NorthSlotOffset); }
|
||
CSlot WSlot() const { return CSlot((_Links & WestSlotMask) >> WestSlotOffset); }
|
||
|
||
bool isSSlotValid() const { return (_Links&SouthSlotMask)!=SouthSlotMask; }
|
||
bool isESlotValid() const { return (_Links&EastSlotMask)!=EastSlotMask; }
|
||
bool isNSlotValid() const { return (_Links&NorthSlotMask)!=NorthSlotMask; }
|
||
bool isWSlotValid() const { return (_Links&WestSlotMask)!=WestSlotMask; }
|
||
|
||
void setSSlot(CSlot const& slot);
|
||
void setESlot(CSlot const& slot);
|
||
void setNSlot(CSlot const& slot);
|
||
void setWSlot(CSlot const& slot);
|
||
|
||
CCellLinkage& operator |=(uint8 links);
|
||
|
||
bool used() const { return _Links!=0xff; }
|
||
|
||
uint8 getLinks() const { return _Links; }
|
||
|
||
void serial(NLMISC::IStream &f);
|
||
|
||
private:
|
||
uint8 _Links;
|
||
};
|
||
|
||
inline
|
||
CCellLinkage::CCellLinkage(uint8 links)
|
||
: _Links(links)
|
||
{
|
||
}
|
||
|
||
inline
|
||
void CCellLinkage::setSSlot(CSlot const& slot)
|
||
{
|
||
_Links = (_Links & (~SouthSlotMask)) + (slot.slot() << SouthSlotOffset);
|
||
}
|
||
|
||
inline
|
||
void CCellLinkage::setESlot(CSlot const& slot)
|
||
{
|
||
_Links = (_Links & (~EastSlotMask)) + (slot.slot() << EastSlotOffset);
|
||
}
|
||
|
||
inline
|
||
void CCellLinkage::setNSlot(CSlot const& slot)
|
||
{
|
||
_Links = (_Links & (~NorthSlotMask)) + (slot.slot() << NorthSlotOffset);
|
||
}
|
||
|
||
inline
|
||
void CCellLinkage::setWSlot(CSlot const& slot)
|
||
{
|
||
_Links = (_Links & (~WestSlotMask)) + (slot.slot() << WestSlotOffset);
|
||
}
|
||
|
||
inline
|
||
CCellLinkage& CCellLinkage::operator |=(uint8 links)
|
||
{
|
||
_Links |= links;
|
||
return *this;
|
||
}
|
||
|
||
inline
|
||
void CCellLinkage::serial(NLMISC::IStream &f)
|
||
{
|
||
f.serial(_Links);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CDirection
|
||
{
|
||
friend class CWorldMap;
|
||
public:
|
||
enum TDeltaDirection
|
||
{
|
||
HALF_TURN_LEFT = 1, // 45 degres
|
||
HALF_TURN_RIGHT = -1, // -45 degres
|
||
TURN_LEFT = 2, // 90 degres
|
||
TURN_RIGHT = -2, // -90 degres
|
||
HALF_TURN = 4 // 180 degres
|
||
};
|
||
|
||
enum TDirection
|
||
{
|
||
E = 0,
|
||
NE = 1,
|
||
N = 2,
|
||
NW = 3,
|
||
W = 4,
|
||
SW = 5,
|
||
S = 6,
|
||
SE = 7,
|
||
UNDEFINED = 8
|
||
};
|
||
|
||
enum TMotifDirection
|
||
{
|
||
SHIFT_E = 1,
|
||
SHIFT_NE = 2,
|
||
SHIFT_N = 4,
|
||
SHIFT_NW = 8,
|
||
SHIFT_W = 16,
|
||
SHIFT_SW = 32,
|
||
SHIFT_S = 64,
|
||
SHIFT_SE = 128,
|
||
SHIFT_UNDEFINED = 256 // be aware, if you use a byte, it makes 0.
|
||
};
|
||
|
||
enum TCost
|
||
{
|
||
NO_COST = 0,
|
||
ORTHO_COST = 2,
|
||
DIAG_COST = 3,
|
||
MAX_COST = 3
|
||
};
|
||
|
||
public:
|
||
explicit CDirection();
|
||
CDirection(CDirection const& dir);
|
||
explicit CDirection(TDirection dir);
|
||
|
||
/// @name user interface assuming the y inversion (sorry).
|
||
//@{
|
||
explicit CDirection(int deltax, int deltay, bool toCalculate);
|
||
|
||
// initialisation with a direction depending on deltas (-1,0 or 1)
|
||
explicit CDirection(int deltax, int deltay);
|
||
|
||
// initialisation with a direction depending on deltas (-1,0 or 1)
|
||
explicit CDirection(CAngle const& angle);
|
||
|
||
CAngle getAngle();
|
||
|
||
sint dx() const;
|
||
sint dy() const;
|
||
void dxdy(int& dx, int& dy);
|
||
//@}
|
||
|
||
bool isValid() { return _value!=UNDEFINED; }
|
||
|
||
// add a number of 45 turn
|
||
void addStep(TDeltaDirection step);
|
||
|
||
NLMISC::CVector2f getDirFloat() const;
|
||
|
||
TDirection getVal() const;
|
||
|
||
TMotifDirection getShift() const;
|
||
|
||
bool operator !=(TDirection dir) const;
|
||
|
||
bool operator != (CDirection const& dir) const;
|
||
|
||
struct CDirectionData
|
||
{
|
||
sint dx;
|
||
sint dy;
|
||
TCost weight;
|
||
};
|
||
static CDirectionData const directionDatas[];
|
||
static TDirection const table[];
|
||
|
||
// used in pacs (nothing to do here but i haven't enought time to rewrite much code)
|
||
uint32 getWeight();
|
||
|
||
static void getDirectionAround(CAngle const& Angle, CDirection& Dir0, CDirection& Dir1);
|
||
|
||
private:
|
||
void setDxDy(int deltax, int deltay);
|
||
|
||
TDirection _value;
|
||
};
|
||
|
||
inline
|
||
CDirection::CDirection()
|
||
: _value(UNDEFINED)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CDirection::CDirection(CDirection const& dir)
|
||
: _value(dir._value)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CDirection::CDirection(TDirection dir)
|
||
: _value(dir)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(dir>=E && dir<=UNDEFINED);
|
||
#endif
|
||
}
|
||
|
||
inline
|
||
CDirection::CDirection(int deltax, int deltay, bool toCalculate)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(deltax!=0 || deltay!=0);
|
||
#endif
|
||
uint absDeltax = abs(deltax);
|
||
uint absDeltay = abs(deltay);
|
||
|
||
if (deltax!=0 && deltay!=0)
|
||
{
|
||
float ratio = (float)((float)absDeltax/(float)absDeltay);
|
||
if (ratio>=0.4141 && ratio<=2.4145) // cos(PI/8)/sin(PI/8) ou sin(PI/8)/cos(PI/8)
|
||
{
|
||
setDxDy(deltax>0?1:-1, deltay>0?1:-1);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (absDeltax>absDeltay)
|
||
setDxDy(deltax>0?1:-1, 0);
|
||
else
|
||
setDxDy(0, deltay>0?1:-1);
|
||
}
|
||
|
||
inline
|
||
CDirection::CDirection(int deltax, int deltay)
|
||
{
|
||
setDxDy(deltax, deltay);
|
||
}
|
||
|
||
inline
|
||
CDirection::CDirection(CAngle const& angle)
|
||
{
|
||
_value = (TDirection)((((sint32)angle.asRawSint16()+65536+4096)/8192)&7); // add 4096 to have a correct angle magnet.
|
||
}
|
||
|
||
inline
|
||
CAngle CDirection::getAngle()
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(isValid());
|
||
#endif
|
||
return CAngle(_value*8192);
|
||
}
|
||
|
||
inline
|
||
sint CDirection::dx() const
|
||
{
|
||
return directionDatas[_value].dx;
|
||
}
|
||
|
||
inline
|
||
sint CDirection::dy() const
|
||
{
|
||
return directionDatas[_value].dy;
|
||
}
|
||
|
||
inline
|
||
void CDirection::dxdy(int& dx, int& dy)
|
||
{
|
||
CDirectionData const& direction = directionDatas[_value];
|
||
dx = direction.dx;
|
||
dy = direction.dy;
|
||
}
|
||
|
||
inline
|
||
void CDirection::addStep(TDeltaDirection step)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(isValid());
|
||
#endif
|
||
_value = (TDirection)((_value+step)&7);
|
||
}
|
||
|
||
inline
|
||
NLMISC::CVector2f CDirection::getDirFloat() const
|
||
{
|
||
return NLMISC::CVector2f((float)dx(), (float)dy());
|
||
}
|
||
|
||
inline
|
||
CDirection::TDirection CDirection::getVal() const
|
||
{
|
||
return _value;
|
||
}
|
||
|
||
inline
|
||
CDirection::TMotifDirection CDirection::getShift() const
|
||
{
|
||
return (TMotifDirection)(1<<_value);
|
||
}
|
||
|
||
inline
|
||
bool CDirection::operator !=(TDirection dir) const
|
||
{
|
||
return _value!=dir;
|
||
}
|
||
|
||
inline
|
||
bool CDirection::operator != (CDirection const& dir) const
|
||
{
|
||
return _value!=dir._value;
|
||
}
|
||
|
||
inline
|
||
uint32 CDirection::getWeight()
|
||
{
|
||
return directionDatas[_value].weight;
|
||
}
|
||
|
||
inline
|
||
void CDirection::getDirectionAround(CAngle const& Angle, CDirection& Dir0, CDirection& Dir1)
|
||
{
|
||
sint value = Angle.asRawSint16()&(~16383); //8191);
|
||
Dir0 = CDirection(CAngle(value));
|
||
value += 16384; //8192;
|
||
Dir1 = CDirection(CAngle(value));
|
||
}
|
||
|
||
inline
|
||
void CDirection::setDxDy(int deltax, int deltay)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert( deltax>=-1 && deltax<=1 && deltay>=-1 && deltay<=1);
|
||
#endif
|
||
_value = table[1+deltax+(1+deltay)*3];
|
||
#ifdef NL_DEBUG
|
||
nlassert(dx()==deltax && dy()==deltay);
|
||
#endif
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A map of accessible positions near a given position
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CNeighbourhood
|
||
{
|
||
public:
|
||
/// One bit per direction
|
||
bool isValid(CDirection::TDirection dir) const;
|
||
bool isValid(CDirection const& dir) const;
|
||
void set(CDirection::TDirection dir);
|
||
CNeighbourhood();
|
||
|
||
private:
|
||
CNeighbourhood(uint32 neighb);
|
||
|
||
/// 8 bits for 8 directions
|
||
uint32 Neighb;
|
||
};
|
||
|
||
inline
|
||
bool CNeighbourhood::isValid(CDirection::TDirection dir) const
|
||
{
|
||
return (Neighb&CDirection(dir).getShift())!=0;
|
||
}
|
||
|
||
inline
|
||
bool CNeighbourhood::isValid(CDirection const& dir) const
|
||
{
|
||
return (Neighb&dir.getShift())!=0;
|
||
}
|
||
|
||
inline
|
||
void CNeighbourhood::set(CDirection::TDirection dir)
|
||
{
|
||
Neighb|=CDirection(dir).getShift();
|
||
}
|
||
|
||
inline
|
||
CNeighbourhood::CNeighbourhood()
|
||
: Neighb(0)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CNeighbourhood::CNeighbourhood(uint32 neighb)
|
||
: Neighb(neighb)
|
||
{
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A slot, defining pacs position and linkage to other slots
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CUnitSlot
|
||
{
|
||
public:
|
||
// 12 bits 0-11 : instance id
|
||
// 12 bits 12-23 : surface id
|
||
// 2 bits 24-25 : north link
|
||
// 2 bits 26-27 : east link
|
||
// 2 bits 28-29 : south link
|
||
// 2 bits 30-31 : west link
|
||
enum
|
||
{
|
||
InstanceIdOffset = 0,
|
||
InstanceIdMask = 0x00000fff,
|
||
InstanceIdMax = 4096,
|
||
|
||
SurfaceIdOffset = 12,
|
||
SurfaceIdMask = 0x00fff000,
|
||
SurfaceIdMax = 4096,
|
||
|
||
SlotOffset = 24,
|
||
SlotMask = 0xff000000
|
||
};
|
||
|
||
// 6 bits 0-5 topology
|
||
// 2 bits 6-7 gabarit
|
||
enum
|
||
{
|
||
TopologyMask = 0x3f,
|
||
GabaritMask = 0xc0,
|
||
GabaritShift = 6,
|
||
};
|
||
|
||
// 1 bit 0 interior
|
||
// 1 bit 1 water
|
||
// 1 bit 2 nogo
|
||
// 13 bits 3-15 height
|
||
enum
|
||
{
|
||
InteriorMask = 0x0001,
|
||
WaterMask = 0x0002,
|
||
NoGoMask = 0x0004,
|
||
HeightMask = 0xfff8,
|
||
HeightShift = 3,
|
||
};
|
||
|
||
public:
|
||
/// @name Constructors
|
||
//@{
|
||
explicit CUnitSlot();
|
||
explicit CUnitSlot(uint instanceId, uint surfaceId);
|
||
explicit CUnitSlot(NLPACS::UGlobalPosition const& pos);
|
||
//@}
|
||
|
||
// Selectors
|
||
uint instanceId() const { return (_Id&InstanceIdMask) >> InstanceIdOffset; }
|
||
uint surfaceId () const { return (_Id&SurfaceIdMask) >> SurfaceIdOffset; }
|
||
uint height () const { return _Height >> HeightShift; }
|
||
|
||
CCellLinkage& cellLink() { return *((CCellLinkage*)(((char*)&_Id)+3)); }
|
||
CCellLinkage getCellLink() const { return *((CCellLinkage*)(((char*)&_Id)+3)); }
|
||
uint topology() const { return (_Topology & TopologyMask); }
|
||
uint gabarit() const { return (_Topology & GabaritMask) >> GabaritShift; }
|
||
bool interior() const { return (_Height & InteriorMask) != 0; }
|
||
bool water() const { return (_Height & WaterMask) != 0; }
|
||
bool nogo() const { return (_Height & NoGoMask) != 0; }
|
||
|
||
/// @name Mutators
|
||
//@{
|
||
void setInstanceId(uint instanceId);
|
||
void setSurface(uint surfaceId);
|
||
void setTopology(uint topology);
|
||
void setGabarit(uint gabarit);
|
||
void setHeight(sint height);
|
||
void setInterior(bool interior);
|
||
void setWater(bool water);
|
||
void setNoGo(bool nogo);
|
||
void reset();
|
||
//@}
|
||
|
||
bool used() const;
|
||
bool hasSameSurface(const CUnitSlot &slot) const;
|
||
|
||
void serial(NLMISC::IStream &f);
|
||
|
||
private:
|
||
// _Id is divided this way
|
||
// bits 0-11 : instance id
|
||
// bits 12-23 : surface id
|
||
// bits 24-25 : north link
|
||
// bits 26-27 : east link
|
||
// bits 28-29 : south link
|
||
// bits 30-31 : west link
|
||
uint32 _Id;
|
||
|
||
// 6 bits 0-5 topology
|
||
// 2 bits 6-7 gabarit
|
||
uint8 _Topology;
|
||
|
||
// 1 bit 0 interior
|
||
// 1 bit 1 water
|
||
// 1 bit 2 nogo
|
||
// 13 bits 3-15 height
|
||
sint16 _Height;
|
||
};
|
||
// a cell is composed of units of 3 slots
|
||
typedef CUnitSlot TCellUnit[3];
|
||
|
||
inline
|
||
CUnitSlot::CUnitSlot()
|
||
: _Id(0xffffffff)
|
||
, _Topology(0)
|
||
, _Height(0)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CUnitSlot::CUnitSlot(uint instanceId, uint surfaceId)
|
||
: _Topology(0)
|
||
, _Height(0)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(instanceId<InstanceIdMax);
|
||
nlassert(surfaceId<SurfaceIdMax);
|
||
#endif
|
||
_Id = SlotMask + (instanceId << InstanceIdOffset) + (surfaceId << SurfaceIdOffset);
|
||
}
|
||
|
||
inline
|
||
CUnitSlot::CUnitSlot(NLPACS::UGlobalPosition const& pos)
|
||
: _Topology(0)
|
||
, _Height(0)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(pos.InstanceId < InstanceIdMax);
|
||
nlassert(pos.LocalPosition.Surface < SurfaceIdMax);
|
||
#endif
|
||
_Id=SlotMask+(pos.InstanceId<<InstanceIdOffset)+(pos.LocalPosition.Surface<<SurfaceIdOffset);
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setInstanceId(uint instanceId)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(instanceId < InstanceIdMax);
|
||
#endif
|
||
_Id = (_Id & (~InstanceIdMask)) + (instanceId << InstanceIdOffset);
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setSurface(uint surfaceId)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(surfaceId < SurfaceIdMax);
|
||
#endif
|
||
_Id = (_Id & (~SurfaceIdMask)) + (surfaceId << SurfaceIdOffset);
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setTopology(uint topology)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(topology < 63);
|
||
#endif
|
||
_Topology = (_Topology & (~TopologyMask)) + (uint8)topology;
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setGabarit(uint gabarit)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(gabarit < 4);
|
||
#endif
|
||
_Topology = (_Topology & (~GabaritMask)) | (uint8)(gabarit << GabaritShift);
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setHeight(sint height)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(height >= -4096 && height <= 4095);
|
||
#endif
|
||
_Height = (_Height & (~HeightMask)) | (sint16)(height << HeightShift);
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setInterior(bool interior)
|
||
{
|
||
if (interior)
|
||
_Height |= InteriorMask;
|
||
else
|
||
_Height &= ~InteriorMask;
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setWater(bool water)
|
||
{
|
||
if (water)
|
||
_Height |= WaterMask;
|
||
else
|
||
_Height &= ~WaterMask;
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::setNoGo(bool nogo)
|
||
{
|
||
if (nogo)
|
||
_Height |= NoGoMask;
|
||
else
|
||
_Height &= ~NoGoMask;
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::reset()
|
||
{
|
||
_Id = 0xffffffff;
|
||
_Topology = 0;
|
||
_Height = 0;
|
||
}
|
||
|
||
inline
|
||
bool CUnitSlot::used() const
|
||
{
|
||
return _Id != 0xffffffff;
|
||
}
|
||
|
||
inline
|
||
bool CUnitSlot::hasSameSurface(const CUnitSlot &slot) const
|
||
{
|
||
return ((slot._Id ^ _Id) & (~SlotMask)) == 0;
|
||
}
|
||
|
||
inline
|
||
void CUnitSlot::serial(NLMISC::IStream &f)
|
||
{
|
||
f.serial(_Id);
|
||
f.serial(_Topology);
|
||
f.serial(_Height);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CMapPosition;
|
||
|
||
typedef sint32 TMapCoordType;
|
||
|
||
/**
|
||
* A simple 1 axis coordinate
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CMapCoord
|
||
{
|
||
friend class CMapPosition;
|
||
public:
|
||
explicit CMapCoord(uint scellId, uint cellId, uint unitId);
|
||
|
||
private:
|
||
explicit CMapCoord() : c(0) { }
|
||
explicit CMapCoord(CAICoord const& aiCoord) : c((sint)(floor(aiCoord.asDouble()+0.5))) { }
|
||
explicit CMapCoord(sint cc) : c(cc) { }
|
||
|
||
uint cellIdMask(uint val) const;
|
||
uint fullCellIdMask(uint val) const;
|
||
|
||
uint toUnitId(uint val) const;
|
||
uint toCellId(uint val) const;
|
||
uint toSuperCellId(uint val) const;
|
||
|
||
uint unitIdToUInt(uint val) const;
|
||
uint cellIdToUInt(uint val) const;
|
||
uint superCellIdToUInt(uint val) const;
|
||
uint fullCellIdToUInt(uint val) const;
|
||
|
||
TMapCoordType& cRef();
|
||
|
||
public:
|
||
uint getUnitId () const { return unitIdToUInt(c); }
|
||
uint getCellId () const { return cellIdToUInt(c); }
|
||
uint getSuperCellId () const { return superCellIdToUInt(c); }
|
||
uint getFullCellId () const { return fullCellIdToUInt(c); }
|
||
|
||
void setUnitId(uint id) { c = fullCellIdMask(c) | toUnitId(id); }
|
||
void setCellId(uint id) { c = cellIdMask(c) | toCellId(id); }
|
||
|
||
bool operator ==(CMapCoord const& cc) const { return c == cc.c; }
|
||
bool operator !=(CMapCoord const& cc) const { return c != cc.c; }
|
||
CMapCoord operator -(CMapCoord const& cc) const { return CMapCoord(c-cc.c); }
|
||
|
||
TMapCoordType const& get() const { return c; }
|
||
|
||
private:
|
||
// coordinate
|
||
TMapCoordType c;
|
||
};
|
||
|
||
inline
|
||
CMapCoord::CMapCoord(uint scellId, uint cellId, uint unitId)
|
||
: c(toSuperCellId(scellId) + toCellId(cellId) + toUnitId(unitId))
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(scellId < 256);
|
||
#endif
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::cellIdMask(uint val) const
|
||
{
|
||
return val&0xff0f;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::fullCellIdMask(uint val) const
|
||
{
|
||
return val&0x0fffffff0;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::toUnitId(uint val) const
|
||
{
|
||
return val&0x0f;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::toCellId(uint val) const
|
||
{
|
||
return (val<<4)&0x0f0;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::toSuperCellId(uint val) const
|
||
{
|
||
return (val<<8)&0x0ffff;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::unitIdToUInt(uint val) const
|
||
{
|
||
return val&0x0f;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::cellIdToUInt(uint val) const
|
||
{
|
||
return (val>>4)&0xf;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::superCellIdToUInt(uint val) const
|
||
{
|
||
return (val>>8)&0x0ff;
|
||
}
|
||
|
||
inline
|
||
uint CMapCoord::fullCellIdToUInt(uint val) const
|
||
{
|
||
return (val>>4)&0x0fff;
|
||
}
|
||
|
||
inline
|
||
TMapCoordType& CMapCoord::cRef()
|
||
{
|
||
return c;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A map position, consisting of 2 axis coordinates
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CMapPosition
|
||
{
|
||
friend class RYPACSCRUNCH::CPacsCruncher;
|
||
public:
|
||
CMapPosition() { }
|
||
CMapPosition(sint x, sint y);
|
||
CMapPosition(CMapCoord const& x, CMapCoord const& y);
|
||
CMapPosition(CMapPosition const& pos);
|
||
CMapPosition(NLMISC::CVectorD const& pos);
|
||
CMapPosition(CAIVector const& pos);
|
||
CMapPosition(CAICoord const& x, CAICoord const& y);
|
||
|
||
NLMISC::CVectorD toVectorD() const;
|
||
NLMISC::CVector2d toVector2d() const;
|
||
CAIVector toAIVector() const;
|
||
|
||
std::string toString() const;
|
||
|
||
void setUnitId(uint const xId, uint const yId);
|
||
void setNullUnitId();
|
||
|
||
CMapPosition stepCell(sint dx, sint dy) const;
|
||
|
||
bool hasSameFullCellId(CMapPosition const& other) const;
|
||
|
||
CMapPosition operator -(CMapPosition const& other) const;
|
||
bool operator ==(CMapPosition const& cc) const;
|
||
bool operator !=(CMapPosition const& cc) const;
|
||
|
||
CMapCoord const& xCoord() const { return _x; }
|
||
CMapCoord const& yCoord() const { return _y; }
|
||
|
||
TMapCoordType const& x() const { return _x.get(); }
|
||
TMapCoordType const& y() const { return _y.get(); }
|
||
|
||
uint32 superCellFastIndex() const;
|
||
uint32 rootCellFastIndex() const;
|
||
uint32 cellUnitFastIndex() const;
|
||
|
||
CMapPosition step(sint dx, sint dy) const;
|
||
|
||
CMapPosition getStepS() const { return step(0, -1); }
|
||
CMapPosition getStepN() const { return step(0, +1); }
|
||
CMapPosition getStepE() const { return step(+1, 0); }
|
||
CMapPosition getStepW() const { return step(-1, 0); }
|
||
protected:
|
||
|
||
// return if we have changed of RootCell ..
|
||
bool stepS() { _y.cRef()-=1; return ((_y.cRef()&0xf)==0xf); }
|
||
bool stepN() { _y.cRef()+=1; return ((_y.cRef()&0xf)==0x0); }
|
||
bool stepW() { _x.cRef()-=1; return ((_x.cRef()&0xf)==0xf); }
|
||
bool stepE() { _x.cRef()+=1; return ((_x.cRef()&0xf)==0x0); }
|
||
|
||
private:
|
||
CMapCoord _x;
|
||
CMapCoord _y;
|
||
};
|
||
|
||
inline
|
||
CMapPosition::CMapPosition(sint x, sint y)
|
||
: _x(CMapCoord(x))
|
||
, _y(CMapCoord(y))
|
||
{
|
||
}
|
||
|
||
inline
|
||
CMapPosition::CMapPosition(CMapCoord const& x, CMapCoord const& y)
|
||
: _x(x)
|
||
, _y(y)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CMapPosition::CMapPosition(CMapPosition const& pos)
|
||
: _x(pos._x)
|
||
, _y(pos._y)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CMapPosition::CMapPosition(NLMISC::CVectorD const& pos)
|
||
: _x((uint)floor((pos.x - WorldStartOffset.x)/WorldGridResolution + 0.5))
|
||
, _y((uint)floor((pos.y - WorldStartOffset.y)/WorldGridResolution + 0.5))
|
||
{
|
||
}
|
||
|
||
inline
|
||
CMapPosition::CMapPosition(CAIVector const& pos)
|
||
: _x(pos.x())
|
||
, _y(pos.y())
|
||
{
|
||
}
|
||
|
||
inline
|
||
CMapPosition::CMapPosition(CAICoord const& x, CAICoord const& y)
|
||
: _x(x)
|
||
, _y(y)
|
||
{
|
||
}
|
||
|
||
inline
|
||
NLMISC::CVectorD CMapPosition::toVectorD() const
|
||
{
|
||
return NLMISC::CVectorD(WorldStartOffset.x + _x.get()*WorldGridResolution, WorldStartOffset.y + _y.get()*WorldGridResolution, 0.0);
|
||
}
|
||
|
||
inline
|
||
NLMISC::CVector2d CMapPosition::toVector2d() const
|
||
{
|
||
return NLMISC::CVector2d(WorldStartOffset.x + _x.get()*WorldGridResolution, WorldStartOffset.y + _y.get()*WorldGridResolution);
|
||
}
|
||
|
||
inline
|
||
CAIVector CMapPosition::toAIVector() const
|
||
{
|
||
return CAIVector(WorldStartOffset.x + _x.get()*WorldGridResolution, WorldStartOffset.y + _y.get()*WorldGridResolution);
|
||
}
|
||
|
||
inline
|
||
std::string CMapPosition::toString() const
|
||
{
|
||
return toAIVector().toString();
|
||
}
|
||
|
||
inline
|
||
void CMapPosition::setUnitId(uint const xId, uint const yId)
|
||
{
|
||
_x.setUnitId(xId);
|
||
_y.setUnitId(yId);
|
||
}
|
||
|
||
inline
|
||
void CMapPosition::setNullUnitId()
|
||
{
|
||
_x.setUnitId(0);
|
||
_y.setUnitId(0);
|
||
}
|
||
|
||
inline
|
||
CMapPosition CMapPosition::stepCell(sint dx, sint dy) const
|
||
{
|
||
CMapPosition newMapPos(xCoord().get()+(dx<<4),yCoord().get()+(dy<<4));
|
||
newMapPos.setNullUnitId();
|
||
return newMapPos;
|
||
}
|
||
|
||
inline
|
||
bool CMapPosition::hasSameFullCellId(CMapPosition const& other) const
|
||
{
|
||
return ( _x.getFullCellId()==other._x.getFullCellId() && _y.getFullCellId()==other._y.getFullCellId() );
|
||
}
|
||
|
||
inline
|
||
CMapPosition CMapPosition::operator -(CMapPosition const& other) const
|
||
{
|
||
return CMapPosition(_x-other._x,_y-other._y);
|
||
}
|
||
|
||
inline
|
||
bool CMapPosition::operator ==(CMapPosition const& cc) const
|
||
{
|
||
return _x==cc._x && _y==cc._y;
|
||
}
|
||
|
||
inline
|
||
bool CMapPosition::operator !=(CMapPosition const& cc) const
|
||
{
|
||
return _x!=cc._x || _y!=cc._y;
|
||
}
|
||
|
||
inline
|
||
uint32 CMapPosition::superCellFastIndex() const
|
||
{
|
||
return ((((uint)y())&(0x0ff<<8)) + xCoord().getSuperCellId());
|
||
}
|
||
|
||
inline
|
||
uint32 CMapPosition::rootCellFastIndex() const
|
||
{
|
||
return ((((uint)y())&0x0f<<4) + xCoord().getCellId());
|
||
}
|
||
|
||
inline
|
||
uint32 CMapPosition::cellUnitFastIndex() const
|
||
{
|
||
return ((yCoord().getUnitId()<<4) + xCoord().getUnitId());
|
||
}
|
||
|
||
inline
|
||
CMapPosition CMapPosition::step(sint dx, sint dy) const
|
||
{
|
||
return CMapPosition(_x.get() + dx, _y.get() + dy);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* Motion map interface
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CGridDirectionLayer
|
||
: public I16x16Layer
|
||
{
|
||
public:
|
||
CDirection getDirection(int y, int x) const;
|
||
CDirection getDirection(CMapPosition const& pos) const;
|
||
|
||
void setDirection(int y, int x, CDirection dir);
|
||
};
|
||
|
||
inline
|
||
CDirection CGridDirectionLayer::getDirection(int y, int x) const
|
||
{
|
||
return CDirection((CDirection::TDirection)get(y, x));
|
||
}
|
||
|
||
inline
|
||
CDirection CGridDirectionLayer::getDirection(CMapPosition const& pos) const
|
||
{
|
||
return CDirection((CDirection::TDirection)get(pos.yCoord().getUnitId(), pos.xCoord().getUnitId()));
|
||
}
|
||
|
||
inline
|
||
void CGridDirectionLayer::setDirection(int y, int x, CDirection dir)
|
||
{
|
||
this->set((uint)y, (uint)x, (sint)dir.getVal());
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CDirectionLayer
|
||
{
|
||
public:
|
||
CDirectionLayer();
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
CGridDirectionLayer* getGridLayer(int y, int x);
|
||
void setGridLayer(int y, int x, I16x16Layer* layer);
|
||
|
||
void dump();
|
||
|
||
private:
|
||
// Grid[1][1] is central cell
|
||
I16x16Layer *Grid[3][3];
|
||
};
|
||
|
||
inline
|
||
CDirectionLayer::CDirectionLayer()
|
||
{
|
||
uint i;
|
||
for (i=0; i<9; ++i)
|
||
Grid[0][i] = NULL;
|
||
}
|
||
|
||
inline
|
||
CGridDirectionLayer* CDirectionLayer::getGridLayer(int y, int x)
|
||
{
|
||
return static_cast<CGridDirectionLayer*>(Grid[y][x]);
|
||
}
|
||
|
||
inline
|
||
void CDirectionLayer::setGridLayer(int y, int x, I16x16Layer* layer)
|
||
{
|
||
Grid[y][x] = layer;
|
||
}
|
||
|
||
inline
|
||
void CDirectionLayer::dump()
|
||
{
|
||
char output[16*3][16*3];
|
||
for (sint i=2; i>=0; --i)
|
||
for (sint j=0; j<3; ++j)
|
||
for (sint y=15; y>=0; --y)
|
||
for (sint x=0; x<16; ++x)
|
||
{
|
||
CGridDirectionLayer* gridDirectionLayer = getGridLayer(i,j);
|
||
CDirection motion;
|
||
|
||
if (gridDirectionLayer)
|
||
motion = gridDirectionLayer->getDirection(y,x);
|
||
|
||
switch (motion.getVal())
|
||
{
|
||
case CDirection::N:
|
||
output[y+i*16][x+j*16] = '^';
|
||
break;
|
||
case CDirection::S:
|
||
output[y+i*16][x+j*16] = 'v';
|
||
break;
|
||
case CDirection::E:
|
||
output[y+i*16][x+j*16] = '>';
|
||
break;
|
||
case CDirection::W:
|
||
output[y+i*16][x+j*16] = '<';
|
||
break;
|
||
case CDirection::NE:
|
||
output[y+i*16][x+j*16] = '7';
|
||
break;
|
||
case CDirection::SW:
|
||
output[y+i*16][x+j*16] = 'L';
|
||
break;
|
||
case CDirection::NW:
|
||
output[y+i*16][x+j*16] = 'r';
|
||
break;
|
||
case CDirection::SE:
|
||
output[y+i*16][x+j*16] = '\\';
|
||
break;
|
||
case 255:
|
||
output[y+i*16][x+j*16] = ' ';
|
||
break;
|
||
default:
|
||
output[y+i*16][x+j*16] = 'o';
|
||
break;
|
||
}
|
||
}
|
||
|
||
char op[256];
|
||
nlinfo(" \t0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF");
|
||
|
||
for (sint i=47; i>=0; --i)
|
||
{
|
||
sint j;
|
||
for (j=0; j<48; ++j)
|
||
op[j] = output[i][j];
|
||
op[j] = '\0';
|
||
nlinfo("%04X\t%s", (i&15), op);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CDirectionMap
|
||
{
|
||
public:
|
||
CDirectionLayer* Layers[3];
|
||
|
||
CDirectionMap();
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
void dump();
|
||
};
|
||
|
||
inline
|
||
CDirectionMap::CDirectionMap()
|
||
{
|
||
Layers[0] = NULL;
|
||
Layers[1] = NULL;
|
||
Layers[2] = NULL;
|
||
}
|
||
|
||
inline
|
||
void CDirectionMap::dump()
|
||
{
|
||
for (uint i=0; i<3; ++i)
|
||
{
|
||
nlinfo("Layer %d", i);
|
||
if (Layers[i] != NULL)
|
||
Layers[i]->dump();
|
||
else
|
||
nlinfo("Empty");
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CWorldMap;
|
||
class CRootCell;
|
||
class CWorldPosition;
|
||
|
||
class CTopology
|
||
{
|
||
public:
|
||
|
||
/// A topology Id, representing cell and topology
|
||
class TTopologyId
|
||
{
|
||
public:
|
||
enum
|
||
{
|
||
UNDEFINED_TOPOLOGY = 0xffffffff
|
||
};
|
||
|
||
public:
|
||
explicit TTopologyId();
|
||
explicit TTopologyId(CMapPosition const& pos, uint topology);
|
||
// For test only
|
||
explicit TTopologyId(uint32 id);
|
||
|
||
bool haveSameCellPos(TTopologyId const& other) const;
|
||
|
||
CMapPosition getMapPosition() const;
|
||
uint getTopologyIndex() const;
|
||
|
||
bool isValid() const;
|
||
|
||
bool operator <(TTopologyId const& other) const;
|
||
bool operator ==(TTopologyId const& other) const;
|
||
bool operator !=(TTopologyId const& other) const;
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
uint32 getVal() const;
|
||
|
||
private:
|
||
uint32 _value;
|
||
};
|
||
|
||
class TTopologyRef
|
||
: public TTopologyId
|
||
{
|
||
friend class CWorldPosition;
|
||
public:
|
||
TTopologyRef(CWorldPosition const& pos);
|
||
TTopologyRef();
|
||
explicit TTopologyRef(TTopologyId const& id, CRootCell* rootCell);
|
||
CTopology const& getCstTopologyNode() const;
|
||
void setRootCell(CRootCell* rootCell);
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
CRootCell const* getRootCell() const;
|
||
|
||
private:
|
||
TTopologyRef(CWorldPosition const& pos, CRootCell const* rootCell);
|
||
CRootCell const* _RootCell;
|
||
};
|
||
|
||
/// A link to a neighbour, including mean distance to it
|
||
class CNeighbourLink
|
||
{
|
||
public:
|
||
explicit CNeighbourLink();
|
||
explicit CNeighbourLink(TTopologyRef const& ref, float distance);
|
||
CNeighbourLink(CNeighbourLink const& other);
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
TTopologyRef const& getTopologyRef() const;
|
||
|
||
void updateTopologyRef(CWorldMap* worldMapPtr);
|
||
|
||
float getDistance() const;
|
||
|
||
private:
|
||
TTopologyRef _Ref;
|
||
float _Distance;
|
||
};
|
||
|
||
void updateTopologyRef(CWorldMap* worldMapPtr);
|
||
|
||
bool isInInterior() const { return (Flags & Interior) != 0; }
|
||
bool isInWater() const { return (Flags & Water) != 0; }
|
||
bool isInNogo() const { return (Flags & NoGo) != 0; }
|
||
|
||
TAStarFlag getFlags() const { return (TAStarFlag)Flags; }
|
||
|
||
uint32 getMasterTopo(TAStarFlag const& flags) const;
|
||
|
||
uint32 getMasterTopo(bool allowWater, bool allowNoGo) const;
|
||
|
||
uint32& getMasterTopoRef(bool allowWater, bool allowNoGo);
|
||
|
||
bool isCompatible(bool allowWater, bool allowNoGo) const;
|
||
|
||
/// The Id of this topology
|
||
TTopologyId Id;
|
||
/// The direction map to access this topology
|
||
CDirectionMap* DirectionMap;
|
||
/// The neighbour topologies that have access to this topology
|
||
std::vector<CNeighbourLink> Neighbours;
|
||
/// Flags of the topology
|
||
uint16 Flags; // why doing this (uint16), its not align so no gain in memory and it causes access cost !
|
||
/// Master topologies
|
||
uint32 MasterTopL; // only landscape
|
||
uint32 MasterTopLW; // landscape and water
|
||
uint32 MasterTopLN; // landscape and nogo
|
||
uint32 MasterTopLNW; // landscape and water and nogo
|
||
|
||
/// Topology center, for A* purpose
|
||
NLMISC::CVector Position;
|
||
|
||
CTopology();
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
};
|
||
|
||
inline
|
||
CTopology::TTopologyId::TTopologyId()
|
||
: _value(UNDEFINED_TOPOLOGY)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyId::TTopologyId(CMapPosition const& pos, uint topology)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(topology < 256);
|
||
#endif
|
||
_value = (pos.yCoord().getFullCellId() << 20) + (pos.xCoord().getFullCellId() << 8) + topology;
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyId::TTopologyId(uint32 id)
|
||
{
|
||
_value = id;
|
||
}
|
||
|
||
inline
|
||
bool CTopology::TTopologyId::haveSameCellPos(TTopologyId const& other) const
|
||
{
|
||
return ((other._value^_value)&0x0ffffff00)==0;
|
||
}
|
||
|
||
inline
|
||
CMapPosition CTopology::TTopologyId::getMapPosition() const
|
||
{
|
||
return CMapPosition((_value&0x000fff00) >> (8-4),(_value&0xfff00000) >> (20-4));
|
||
}
|
||
|
||
inline
|
||
uint CTopology::TTopologyId::getTopologyIndex() const
|
||
{
|
||
return _value&0x000000ff;
|
||
}
|
||
|
||
inline
|
||
bool CTopology::TTopologyId::isValid() const
|
||
{
|
||
return _value!=UNDEFINED_TOPOLOGY;
|
||
}
|
||
|
||
inline
|
||
bool CTopology::TTopologyId::operator <(TTopologyId const& other) const
|
||
{
|
||
return _value<other._value;
|
||
}
|
||
|
||
inline
|
||
bool CTopology::TTopologyId::operator ==(TTopologyId const& other) const
|
||
{
|
||
return _value==other._value;
|
||
}
|
||
|
||
inline
|
||
bool CTopology::TTopologyId::operator !=(TTopologyId const& other) const
|
||
{
|
||
return _value!=other._value;
|
||
}
|
||
|
||
inline
|
||
void CTopology::TTopologyId::serial(NLMISC::IStream& f)
|
||
{
|
||
f.serial(_value);
|
||
}
|
||
|
||
inline
|
||
uint32 CTopology::TTopologyId::getVal() const
|
||
{
|
||
return _value;
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef::TTopologyRef()
|
||
: _RootCell(NULL)
|
||
, TTopologyId()
|
||
{
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef::TTopologyRef(TTopologyId const& id, CRootCell* rootCell)
|
||
: TTopologyId(id)
|
||
{
|
||
setRootCell(rootCell);
|
||
}
|
||
|
||
inline
|
||
void CTopology::TTopologyRef::setRootCell(CRootCell* rootCell)
|
||
{
|
||
_RootCell = rootCell;
|
||
}
|
||
|
||
inline
|
||
void CTopology::TTopologyRef::serial(NLMISC::IStream& f)
|
||
{
|
||
TTopologyId::serial(f);
|
||
}
|
||
|
||
inline
|
||
CRootCell const* CTopology::TTopologyRef::getRootCell() const
|
||
{
|
||
return _RootCell;
|
||
}
|
||
|
||
inline
|
||
CTopology::CNeighbourLink::CNeighbourLink()
|
||
: _Ref()
|
||
{
|
||
}
|
||
|
||
inline
|
||
CTopology::CNeighbourLink::CNeighbourLink(TTopologyRef const& ref, float distance)
|
||
: _Ref(ref)
|
||
, _Distance(distance)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CTopology::CNeighbourLink::CNeighbourLink(CNeighbourLink const& other)
|
||
: _Ref(other._Ref)
|
||
, _Distance(other._Distance)
|
||
{
|
||
}
|
||
|
||
inline
|
||
void CTopology::CNeighbourLink::serial(NLMISC::IStream& f)
|
||
{
|
||
f.serial(_Ref, _Distance);
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef const& CTopology::CNeighbourLink::getTopologyRef() const
|
||
{
|
||
return _Ref;
|
||
}
|
||
|
||
inline
|
||
float CTopology::CNeighbourLink::getDistance() const
|
||
{
|
||
return _Distance;
|
||
}
|
||
|
||
inline
|
||
void CTopology::updateTopologyRef(CWorldMap* worldMapPtr)
|
||
{
|
||
std::vector<CNeighbourLink>::iterator it=Neighbours.begin(), itEnd=Neighbours.end();
|
||
while (it!=itEnd)
|
||
{
|
||
(*it).updateTopologyRef(worldMapPtr);
|
||
++it;
|
||
}
|
||
}
|
||
|
||
inline
|
||
uint32 CTopology::getMasterTopo(TAStarFlag const& flags) const
|
||
{
|
||
switch (flags&WaterAndNogo)
|
||
{
|
||
case Nothing:
|
||
default:
|
||
return MasterTopL;
|
||
case Water:
|
||
return MasterTopLW;
|
||
case NoGo:
|
||
return MasterTopLN;
|
||
case WaterAndNogo:
|
||
return MasterTopLNW;
|
||
}
|
||
}
|
||
|
||
inline
|
||
uint32 CTopology::getMasterTopo(bool allowWater, bool allowNoGo) const
|
||
{
|
||
if (allowWater)
|
||
{
|
||
if (allowNoGo)
|
||
return MasterTopLNW;
|
||
return MasterTopLW;
|
||
}
|
||
if (allowNoGo)
|
||
return MasterTopLN;
|
||
return MasterTopL;
|
||
}
|
||
|
||
inline
|
||
uint32& CTopology::getMasterTopoRef(bool allowWater, bool allowNoGo)
|
||
{
|
||
if (allowWater)
|
||
{
|
||
if (allowNoGo)
|
||
return MasterTopLNW;
|
||
return MasterTopLW;
|
||
}
|
||
if (allowNoGo)
|
||
return MasterTopLN;
|
||
return MasterTopL;
|
||
}
|
||
|
||
inline
|
||
bool CTopology::isCompatible(bool allowWater, bool allowNoGo) const
|
||
{
|
||
return (allowWater || !isInWater()) && (allowNoGo || !isInNogo());
|
||
}
|
||
|
||
inline
|
||
CTopology::CTopology()
|
||
: Id()
|
||
, DirectionMap(NULL)
|
||
, Flags(Nothing)
|
||
, MasterTopL(TTopologyId::UNDEFINED_TOPOLOGY)
|
||
, MasterTopLW(TTopologyId::UNDEFINED_TOPOLOGY)
|
||
, MasterTopLN(TTopologyId::UNDEFINED_TOPOLOGY)
|
||
, MasterTopLNW(TTopologyId::UNDEFINED_TOPOLOGY)
|
||
{
|
||
}
|
||
|
||
inline
|
||
void CTopology::serial(NLMISC::IStream& f)
|
||
{
|
||
|
||
uint version = 0;
|
||
|
||
uint16 check = (uint16)'Tp';
|
||
f.serial(check);
|
||
|
||
if (check != (uint16)'TP')
|
||
{
|
||
nlassert(check == (uint16)'Tp');
|
||
version = f.serialVersion(3);
|
||
}
|
||
|
||
f.serial(Id);
|
||
|
||
if (f.isReading())
|
||
{
|
||
delete DirectionMap;
|
||
DirectionMap = NULL;
|
||
}
|
||
|
||
bool present = (DirectionMap != NULL);
|
||
f.serial(present);
|
||
|
||
if (present)
|
||
{
|
||
if (f.isReading())
|
||
DirectionMap = new CDirectionMap();
|
||
|
||
f.serial(*DirectionMap);
|
||
}
|
||
|
||
f.serialCont(Neighbours);
|
||
|
||
f.serial(Position);
|
||
|
||
if (version >= 3)
|
||
{
|
||
f.serial(Flags);
|
||
|
||
f.serial(MasterTopL);
|
||
f.serial(MasterTopLW);
|
||
f.serial(MasterTopLN);
|
||
f.serial(MasterTopLNW);
|
||
}
|
||
else
|
||
{
|
||
nlassert(f.isReading());
|
||
|
||
Flags = Nothing;
|
||
|
||
if (version >= 1)
|
||
{
|
||
bool interior;
|
||
f.serial(interior);
|
||
if (interior)
|
||
Flags |= Interior;
|
||
}
|
||
|
||
if (version >= 2)
|
||
{
|
||
bool water;
|
||
f.serial(water);
|
||
if (water)
|
||
Flags |= Water;
|
||
}
|
||
|
||
MasterTopL = 0;
|
||
MasterTopLW = 0;
|
||
MasterTopLN = 0;
|
||
MasterTopLNW = 0;
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* CWorldPosition, position referenced by a map position and a slot
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CWorldPosition
|
||
: public CMapPosition
|
||
, public CSlot
|
||
{
|
||
friend class CWorldMap;
|
||
friend class RYPACSCRUNCH::CPacsCruncher;
|
||
public:
|
||
explicit CWorldPosition();
|
||
explicit CWorldPosition(sint x, sint y);
|
||
|
||
// resumes that the RootCell is valid;
|
||
CRootCell const* getRootCell() const { return _RootCell; }
|
||
|
||
/// In millimeters.
|
||
sint32 getMetricHeight() const;
|
||
sint32 h() const { return getMetricHeight(); }
|
||
|
||
CCellLinkage const& getCellLinkage() const { return _cellLinkage; }
|
||
|
||
CTopology::TTopologyRef getTopologyRef() const;
|
||
|
||
bool isInInterior() const;
|
||
|
||
CTopology const& getTopologyNode() const;
|
||
|
||
TAStarFlag getFlags() const;
|
||
|
||
/// Get a vector position from a world position
|
||
NLMISC::CVectorD getPosition() const;
|
||
|
||
bool operator ==(CWorldPosition const& cc) const { return CSlot::operator ==(cc) && CMapPosition::operator ==(cc); }
|
||
bool operator !=(CWorldPosition const& cc) const { return CSlot::operator !=(cc) || CMapPosition::operator !=(cc); }
|
||
|
||
private:
|
||
CWorldPosition getPosS() const;
|
||
CWorldPosition getPosN() const;
|
||
CWorldPosition getPosE() const;
|
||
CWorldPosition getPosW() const;
|
||
|
||
void setPosS(CWorldPosition& pos) const;
|
||
void setPosN(CWorldPosition& pos) const;
|
||
void setPosE(CWorldPosition& pos) const;
|
||
void setPosW(CWorldPosition& pos) const;
|
||
|
||
bool moveS();
|
||
bool moveN();
|
||
bool moveE();
|
||
bool moveW();
|
||
|
||
void stepS();
|
||
void stepN();
|
||
void stepE();
|
||
void stepW();
|
||
|
||
CRootCell const* _RootCell;
|
||
CCellLinkage _cellLinkage;
|
||
|
||
explicit CWorldPosition(CRootCell const* cell, CMapPosition const& pos, CSlot const& slot);
|
||
explicit CWorldPosition(CRootCell const* cell, CMapPosition const& pos, CSlot const& slot, bool generationOnly);
|
||
};
|
||
|
||
inline
|
||
CWorldPosition::CWorldPosition()
|
||
: CMapPosition()
|
||
, CSlot()
|
||
, _RootCell(NULL)
|
||
, _cellLinkage(0)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CWorldPosition::CWorldPosition(sint x, sint y)
|
||
: CMapPosition(x, y)
|
||
, CSlot()
|
||
, _RootCell(NULL)
|
||
, _cellLinkage(0)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef CWorldPosition::getTopologyRef() const
|
||
{
|
||
return CTopology::TTopologyRef(*this, getRootCell());
|
||
}
|
||
|
||
inline
|
||
bool CWorldPosition::isInInterior() const
|
||
{
|
||
return getTopologyRef().getCstTopologyNode().isInInterior();
|
||
}
|
||
|
||
inline
|
||
CTopology const& CWorldPosition::getTopologyNode() const
|
||
{
|
||
return getTopologyRef().getCstTopologyNode();
|
||
}
|
||
|
||
inline
|
||
TAStarFlag CWorldPosition::getFlags() const
|
||
{
|
||
return getTopologyRef().getCstTopologyNode().getFlags(); //Flags;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CCompatibleResult
|
||
{
|
||
public:
|
||
CCompatibleResult(TAStarFlag movementFlags = Interior, uint32 choosenMasterTopo = ~0);
|
||
void set(TAStarFlag movementFlags, uint32 choosenMasterTopo);
|
||
void setValid(bool valid = true);
|
||
TAStarFlag const& movementFlags() const;
|
||
uint32 const& choosenMasterTopo() const;
|
||
bool const& isValid() const;
|
||
|
||
private:
|
||
TAStarFlag _MovementFlags;
|
||
uint32 _ChoosenMasterTopo;
|
||
bool _Valid;
|
||
};
|
||
|
||
inline
|
||
CCompatibleResult::CCompatibleResult(TAStarFlag movementFlags, uint32 choosenMasterTopo)
|
||
: _MovementFlags(movementFlags)
|
||
, _ChoosenMasterTopo(choosenMasterTopo)
|
||
, _Valid(false)
|
||
{
|
||
}
|
||
|
||
inline
|
||
void CCompatibleResult::set(TAStarFlag movementFlags, uint32 choosenMasterTopo)
|
||
{
|
||
_MovementFlags = movementFlags;
|
||
_ChoosenMasterTopo = choosenMasterTopo;
|
||
}
|
||
|
||
inline
|
||
void CCompatibleResult::setValid(bool valid)
|
||
{
|
||
_Valid = valid;
|
||
}
|
||
|
||
inline
|
||
TAStarFlag const& CCompatibleResult::movementFlags() const
|
||
{
|
||
return _MovementFlags;
|
||
}
|
||
|
||
inline
|
||
uint32 const& CCompatibleResult::choosenMasterTopo() const
|
||
{
|
||
return _ChoosenMasterTopo;
|
||
}
|
||
|
||
inline
|
||
bool const& CCompatibleResult::isValid() const
|
||
{
|
||
return _Valid;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
@relates CWorldPosition
|
||
*/
|
||
void areCompatiblesWithoutStartRestriction(CWorldPosition const& startPos, CWorldPosition const& endPos, TAStarFlag const& denyflags, CCompatibleResult& res, bool allowStartRestriction = false);
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* CRootCell, interface for all 16x16 cells in world map
|
||
* derivated into CComputeCell (for map computation only), into CSingleLayerCell and CMultiLayerCell
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CRootCell
|
||
{
|
||
public:
|
||
enum TCellType
|
||
{
|
||
Root = 0,
|
||
Compute,
|
||
White,
|
||
SingleLayer,
|
||
MultiLayer
|
||
};
|
||
|
||
public:
|
||
CRootCell(CWorldMap const& worldMapPtr);
|
||
|
||
virtual ~CRootCell() { }
|
||
|
||
void setFlag(uint32 const flag) { _flag = flag; }
|
||
uint32 getFlag() const { return _flag; }
|
||
|
||
sint32 getMetricHeight(CWorldPosition const& wpos) const;
|
||
|
||
CWorldMap const& getWorldMapPtr() const { return _WorldMapPtr; }
|
||
|
||
// mutator (only for build purpose)
|
||
CTopology& getTopologyNode(uint topology);
|
||
CTopology const& getCstTopologyNode(uint topology) const;
|
||
|
||
CTopology::TTopologyId getTopologyId(CWorldPosition const& wpos) const;
|
||
|
||
CTopology::TTopologyRef getTopologyRef(const CWorldPosition&pos) const;
|
||
|
||
CTopology const& getCstTopologyNode(CTopology::TTopologyId const& id) const;
|
||
|
||
std::vector<CTopology>& getTopologiesNodes() { return _TopologiesNodes; }
|
||
std::vector<CTopology> const& getTopologiesNodes() const { return _TopologiesNodes; }
|
||
void setTopologiesNodes(std::vector<CTopology> const& nodes) { _TopologiesNodes = nodes; }
|
||
|
||
CDirectionMap const* getDirectionMap(uint topology) const;
|
||
void setDirectionMap(CDirectionMap* map, uint topology);
|
||
|
||
void updateTopologyRef(CWorldMap* worldMap);
|
||
|
||
CWorldPosition const& getWorldPosition(uint ind) const;
|
||
|
||
void setWorldPosition(CWorldPosition const& pos, uint ind);
|
||
|
||
virtual CCellLinkage getCellLink(CWorldPosition const& wpos) const = 0;
|
||
|
||
virtual uint32 nbUsedSlots(CMapPosition const& pos) const = 0;
|
||
virtual sint32 maxUsedSlot(CMapPosition const& pos) const = 0;
|
||
virtual bool isSlotUsed(CMapPosition const& pos, CSlot const& slot) const = 0;
|
||
|
||
virtual uint getTopology(CWorldPosition const& wpos) const = 0;
|
||
|
||
virtual sint getHeight(CWorldPosition const& wpos) const = 0;
|
||
|
||
// clear height map
|
||
virtual void clearHeightMap() = 0;
|
||
|
||
// serial
|
||
virtual void serial(NLMISC::IStream& f) = 0;
|
||
|
||
// load a cell
|
||
static CRootCell* load(NLMISC::IStream& f, CWorldMap const& worldMap);
|
||
|
||
// save a cell
|
||
static void save(NLMISC::IStream& f, CRootCell* cell);
|
||
|
||
private:
|
||
CWorldMap const& _WorldMapPtr; // his owner map;
|
||
std::vector<CTopology> _TopologiesNodes;
|
||
CWorldPosition _WorldPosition[4]; // 4 random positions for each slots.
|
||
uint32 _flag;
|
||
};
|
||
|
||
inline
|
||
CRootCell::CRootCell(CWorldMap const& worldMapPtr)
|
||
: _WorldMapPtr(worldMapPtr)
|
||
{
|
||
_flag = 0;
|
||
}
|
||
|
||
inline
|
||
sint32 CRootCell::getMetricHeight(CWorldPosition const& wpos) const
|
||
{
|
||
// check if wpos valid
|
||
if (!wpos.isValid())
|
||
return 0;
|
||
|
||
sint32 const z = (getHeight(wpos)*2000 - 1000)&(~3);
|
||
uint const top = getTopology(wpos);
|
||
if (top<_TopologiesNodes.size() && _TopologiesNodes[top].isInInterior())
|
||
return z+2;
|
||
return z;
|
||
}
|
||
|
||
inline
|
||
CTopology& CRootCell::getTopologyNode(uint topology)
|
||
{
|
||
if (topology >= _TopologiesNodes.size())
|
||
_TopologiesNodes.resize(topology+1);
|
||
|
||
return _TopologiesNodes[topology];
|
||
}
|
||
|
||
inline
|
||
CTopology const& CRootCell::getCstTopologyNode(uint topology) const
|
||
{
|
||
#if !FINAL_VERSION
|
||
nlassert(topology < _TopologiesNodes.size());
|
||
#endif
|
||
return _TopologiesNodes[topology];
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyId CRootCell::getTopologyId(CWorldPosition const& wpos) const
|
||
{
|
||
return CTopology::TTopologyId(wpos, getTopology(wpos));
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef CRootCell::getTopologyRef(const CWorldPosition&pos) const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(pos.getRootCell()!=this);
|
||
#endif
|
||
return CTopology::TTopologyRef(pos);
|
||
}
|
||
|
||
inline
|
||
CTopology const& CRootCell::getCstTopologyNode(CTopology::TTopologyId const& id) const
|
||
{
|
||
return getCstTopologyNode(id.getTopologyIndex());
|
||
}
|
||
|
||
inline
|
||
CDirectionMap const* CRootCell::getDirectionMap(uint topology) const
|
||
{
|
||
return (topology<_TopologiesNodes.size()) ? getCstTopologyNode(topology).DirectionMap : NULL;
|
||
}
|
||
|
||
inline
|
||
void CRootCell::setDirectionMap(CDirectionMap* map, uint topology)
|
||
{
|
||
getTopologyNode(topology).DirectionMap = map;
|
||
}
|
||
|
||
inline
|
||
void CRootCell::updateTopologyRef(CWorldMap* worldMap)
|
||
{
|
||
std::vector<CTopology>::iterator it=_TopologiesNodes.begin(), itEnd=_TopologiesNodes.end();
|
||
while (it!=itEnd)
|
||
{
|
||
(*it).updateTopologyRef(worldMap);
|
||
++it;
|
||
}
|
||
}
|
||
|
||
inline
|
||
CWorldPosition const& CRootCell::getWorldPosition(uint ind) const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(ind<4);
|
||
#endif
|
||
return _WorldPosition[ind];
|
||
}
|
||
|
||
inline
|
||
void CRootCell::setWorldPosition(CWorldPosition const& pos, uint ind)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(ind<4);
|
||
#endif
|
||
_WorldPosition[ind] = pos;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A computed 16x16 cell
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CComputeCell
|
||
: public CRootCell
|
||
{
|
||
public:
|
||
CComputeCell(CWorldMap const& worldMapPtr);
|
||
|
||
CCellLinkage getCellLink(CWorldPosition const& wpos) const;
|
||
|
||
uint32 nbUsedSlots(CMapPosition const& pos) const;
|
||
|
||
sint32 maxUsedSlot(CMapPosition const& pos) const;
|
||
|
||
bool isSlotUsed(CMapPosition const& pos, CSlot const& slot) const;
|
||
|
||
uint getTopology(CWorldPosition const& wpos) const;
|
||
|
||
sint getHeight(CWorldPosition const& wpos) const;
|
||
|
||
TCellUnit const& getCellUnitCst(CMapPosition const& pos) const;
|
||
|
||
CUnitSlot const& getUnitSlotCst(CWorldPosition const& wpos) const;
|
||
|
||
TCellUnit& getCellUnit(CMapPosition const& pos);
|
||
|
||
CUnitSlot& getUnitSlot(CWorldPosition const& wpos);
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
void clearHeightMap() { }
|
||
|
||
private:
|
||
TCellUnit const& getCellUnitCst(CWorldPosition const& wpos) const;
|
||
|
||
// a cell is a grid of 16x16 units
|
||
TCellUnit _Grid[16*16];
|
||
};
|
||
|
||
inline
|
||
CComputeCell::CComputeCell(CWorldMap const& worldMapPtr)
|
||
: CRootCell(worldMapPtr)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CCellLinkage CComputeCell::getCellLink(CWorldPosition const& wpos) const
|
||
{
|
||
return getUnitSlotCst(wpos).getCellLink();
|
||
}
|
||
|
||
inline
|
||
uint32 CComputeCell::nbUsedSlots(CMapPosition const& pos) const
|
||
{
|
||
TCellUnit const& cellUnit = getCellUnitCst(pos);
|
||
uint32 count = 0;
|
||
for (uint slot=0; slot<3; ++slot)
|
||
if (cellUnit[slot].getCellLink().used())
|
||
++count;
|
||
return count;
|
||
}
|
||
|
||
inline
|
||
sint32 CComputeCell::maxUsedSlot(CMapPosition const& pos) const
|
||
{
|
||
TCellUnit const& cellUnit = getCellUnitCst(pos);
|
||
sint32 maxs = -1;
|
||
for (uint slot=0; slot<3; ++slot)
|
||
if (cellUnit[slot].getCellLink().used())
|
||
maxs = slot;
|
||
return maxs;
|
||
}
|
||
|
||
inline
|
||
bool CComputeCell::isSlotUsed(CMapPosition const& pos, CSlot const& slot) const
|
||
{
|
||
TCellUnit const& cellUnit = getCellUnitCst(pos);
|
||
return slot.isValid() ? cellUnit[slot.slot()].getCellLink().used() : false;
|
||
}
|
||
|
||
inline
|
||
uint CComputeCell::getTopology(CWorldPosition const& wpos) const
|
||
{
|
||
return getUnitSlotCst(wpos).topology();
|
||
}
|
||
|
||
inline
|
||
sint CComputeCell::getHeight(CWorldPosition const& wpos) const
|
||
{
|
||
return getUnitSlotCst(wpos).height();
|
||
}
|
||
|
||
inline
|
||
TCellUnit const& CComputeCell::getCellUnitCst(CMapPosition const& pos) const
|
||
{
|
||
return _Grid[pos.cellUnitFastIndex()];
|
||
}
|
||
|
||
inline
|
||
CUnitSlot const& CComputeCell::getUnitSlotCst(CWorldPosition const& wpos) const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
return getCellUnitCst(wpos)[wpos.slot()];
|
||
}
|
||
|
||
inline
|
||
TCellUnit& CComputeCell::getCellUnit(CMapPosition const& pos)
|
||
{
|
||
return _Grid[pos.cellUnitFastIndex()];
|
||
}
|
||
|
||
inline
|
||
CUnitSlot& CComputeCell::getUnitSlot(CWorldPosition const& wpos)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
return getCellUnit(wpos)[wpos.slot()];
|
||
}
|
||
|
||
inline
|
||
TCellUnit const& CComputeCell::getCellUnitCst(CWorldPosition const& wpos) const
|
||
{
|
||
return _Grid[wpos.cellUnitFastIndex()];
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A Single layer 16x16 cell that has not walk constraint (map is completely white)
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CWhiteCell
|
||
: public CRootCell
|
||
{
|
||
public:
|
||
CWhiteCell(CWorldMap const& worldMapPtr);
|
||
|
||
CCellLinkage getCellLink(CWorldPosition const& wpos) const;
|
||
|
||
uint32 nbUsedSlots(CMapPosition const& pos) const;
|
||
|
||
sint32 maxUsedSlot(CMapPosition const& pos) const;
|
||
|
||
bool isSlotUsed(CMapPosition const& pos, CSlot const& slot) const;
|
||
|
||
uint getTopology(CWorldPosition const& wpos) const;
|
||
|
||
sint getHeight(CWorldPosition const& wpos) const;
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
void clearHeightMap();
|
||
|
||
void setHeightMap(I16x16Layer* heightMap);
|
||
|
||
private:
|
||
I16x16Layer* _HeightMap;
|
||
};
|
||
|
||
inline
|
||
CWhiteCell::CWhiteCell(CWorldMap const& worldMapPtr)
|
||
: _HeightMap(NULL), CRootCell(worldMapPtr)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CCellLinkage CWhiteCell::getCellLink(CWorldPosition const& wpos) const
|
||
{
|
||
return CCellLinkage(0);
|
||
}
|
||
|
||
inline
|
||
uint32 CWhiteCell::nbUsedSlots(CMapPosition const& pos) const
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
inline
|
||
sint32 CWhiteCell::maxUsedSlot(CMapPosition const& pos) const
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
inline
|
||
bool CWhiteCell::isSlotUsed(CMapPosition const& pos, CSlot const& slot) const
|
||
{
|
||
return slot.slot() == 0;
|
||
}
|
||
|
||
inline
|
||
uint CWhiteCell::getTopology(CWorldPosition const& wpos) const
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
inline
|
||
sint CWhiteCell::getHeight(CWorldPosition const& wpos) const
|
||
{
|
||
return (_HeightMap != NULL) ? _HeightMap->get(wpos.yCoord().getUnitId(), wpos.xCoord().getUnitId()) : 0;
|
||
}
|
||
|
||
inline
|
||
void CWhiteCell::serial(NLMISC::IStream& f)
|
||
{
|
||
f.serialCheck((uint16)'WC');
|
||
if (f.isReading())
|
||
_HeightMap = I16x16Layer::load(f);
|
||
else
|
||
I16x16Layer::save(f, _HeightMap);
|
||
}
|
||
|
||
inline
|
||
void CWhiteCell::clearHeightMap()
|
||
{
|
||
if (_HeightMap)
|
||
delete _HeightMap;
|
||
_HeightMap = NULL;
|
||
}
|
||
|
||
inline
|
||
void CWhiteCell::setHeightMap(I16x16Layer* heightMap)
|
||
{
|
||
_HeightMap = heightMap;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A Single layer 16x16 cell
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CSingleLayerCell
|
||
: public CRootCell
|
||
{
|
||
protected:
|
||
bool testPos(uint i, uint j) const { return (_Map[i] & _MaskMap[j]) != 0; }
|
||
void setPos(uint i, uint j, bool p) { _Map[i] = (p ? (_Map[i] | _MaskMap[j]) : (_Map[i] & (~_MaskMap[j]))); }
|
||
|
||
public:
|
||
CSingleLayerCell(CWorldMap const& worldMapPtr);
|
||
|
||
CCellLinkage getCellLink(CWorldPosition const& wpos) const;
|
||
|
||
uint32 nbUsedSlots(CMapPosition const& pos) const;
|
||
|
||
sint32 maxUsedSlot(CMapPosition const& pos) const;
|
||
|
||
bool isSlotUsed(CMapPosition const& pos, CSlot const& slot) const;
|
||
|
||
uint getTopology(CWorldPosition const& wpos) const;
|
||
|
||
sint getHeight(CWorldPosition const& wpos) const;
|
||
|
||
bool testPos(CMapPosition const& pos) const;
|
||
|
||
void setPos(CMapPosition const& pos, bool p);
|
||
|
||
void setSLink(uint i, bool p) { _SLinks = p ? (_SLinks | _MaskMap[i]) : (_SLinks & (~_MaskMap[i])); }
|
||
void setNLink(uint i, bool p) { _NLinks = p ? (_NLinks | _MaskMap[i]) : (_NLinks & (~_MaskMap[i])); }
|
||
void setELink(uint i, bool p) { _ELinks = p ? (_ELinks | _MaskMap[i]) : (_ELinks & (~_MaskMap[i])); }
|
||
void setWLink(uint i, bool p) { _WLinks = p ? (_WLinks | _MaskMap[i]) : (_WLinks & (~_MaskMap[i])); }
|
||
|
||
void setTopologies(I16x16Layer* topology);
|
||
|
||
void setHeightMap(I16x16Layer* heightMap);
|
||
|
||
virtual void serial(NLMISC::IStream& f);
|
||
|
||
void clearHeightMap();
|
||
|
||
private:
|
||
/// The map of accessible positions
|
||
uint16 _Map[16];
|
||
/// The north links, true if north position is accessible
|
||
uint16 _SLinks;
|
||
uint16 _NLinks;
|
||
uint16 _ELinks;
|
||
uint16 _WLinks;
|
||
|
||
// topology layer
|
||
I16x16Layer* _Topologies;
|
||
|
||
// height map
|
||
I16x16Layer* _HeightMap;
|
||
|
||
static uint16 _MaskMap[16];
|
||
static bool _Initialized;
|
||
};
|
||
|
||
inline
|
||
CSingleLayerCell::CSingleLayerCell(CWorldMap const& worldMapPtr)
|
||
: CRootCell(worldMapPtr)
|
||
{
|
||
for (uint i=0; i<16; ++i)
|
||
_Map[i] = 0;
|
||
|
||
_SLinks = 0;
|
||
_NLinks = 0;
|
||
_ELinks = 0;
|
||
_WLinks = 0;
|
||
_Topologies = NULL;
|
||
_HeightMap = NULL;
|
||
|
||
if (!_Initialized)
|
||
{
|
||
for (uint i=0; i<16; ++i)
|
||
_MaskMap[i] = (1 << (15-i));
|
||
_Initialized = true;
|
||
}
|
||
}
|
||
|
||
inline
|
||
CCellLinkage CSingleLayerCell::getCellLink(CWorldPosition const& wpos) const
|
||
{
|
||
uint xi = wpos.xCoord().getUnitId();
|
||
uint yi = wpos.yCoord().getUnitId();
|
||
|
||
CCellLinkage l(0);
|
||
|
||
l |= ((xi > 0 && testPos(yi, xi-1)) || (xi == 0 && (_WLinks&_MaskMap[yi]))) ? 0 : CCellLinkage::WestSlotMask;
|
||
l |= ((xi < 15 && testPos(yi, xi+1)) || (xi == 15 && (_ELinks&_MaskMap[yi]))) ? 0 : CCellLinkage::EastSlotMask;
|
||
l |= ((yi > 0 && testPos(yi-1, xi)) || (yi == 0 && (_SLinks&_MaskMap[xi]))) ? 0 : CCellLinkage::SouthSlotMask;
|
||
l |= ((yi < 15 && testPos(yi+1, xi)) || (yi == 15 && (_NLinks&_MaskMap[xi]))) ? 0 : CCellLinkage::NorthSlotMask;
|
||
|
||
return l;
|
||
}
|
||
|
||
inline
|
||
uint32 CSingleLayerCell::nbUsedSlots(CMapPosition const& pos) const
|
||
{
|
||
return testPos(pos) ? 1 : 0;
|
||
}
|
||
|
||
inline
|
||
sint32 CSingleLayerCell::maxUsedSlot(CMapPosition const& pos) const
|
||
{
|
||
return testPos(pos) ? 0 : -1;
|
||
}
|
||
|
||
inline
|
||
bool CSingleLayerCell::isSlotUsed(CMapPosition const& pos, CSlot const& slot) const
|
||
{
|
||
return slot.slot() == 0 && testPos(pos);
|
||
}
|
||
|
||
inline
|
||
uint CSingleLayerCell::getTopology(CWorldPosition const& wpos) const
|
||
{
|
||
return (_Topologies != NULL) ? _Topologies->get(wpos.yCoord().getUnitId(), wpos.xCoord().getUnitId()) : 0;
|
||
}
|
||
|
||
inline
|
||
sint CSingleLayerCell::getHeight(CWorldPosition const& wpos) const
|
||
{
|
||
return (_HeightMap != NULL) ? _HeightMap->get(wpos.yCoord().getUnitId(), wpos.xCoord().getUnitId()) : 0;
|
||
}
|
||
|
||
inline
|
||
bool CSingleLayerCell::testPos(CMapPosition const& pos) const
|
||
{
|
||
return testPos(pos.yCoord().getUnitId(), pos.xCoord().getUnitId());
|
||
}
|
||
|
||
inline
|
||
void CSingleLayerCell::setPos(CMapPosition const& pos, bool p)
|
||
{
|
||
setPos(pos.yCoord().getUnitId(), pos.xCoord().getUnitId(), p);
|
||
}
|
||
|
||
inline
|
||
void CSingleLayerCell::setTopologies(I16x16Layer* topology)
|
||
{
|
||
delete _Topologies;
|
||
_Topologies = topology;
|
||
}
|
||
|
||
inline
|
||
void CSingleLayerCell::setHeightMap(I16x16Layer* heightMap)
|
||
{
|
||
if (_HeightMap)
|
||
delete _HeightMap;
|
||
_HeightMap = heightMap;
|
||
}
|
||
|
||
inline
|
||
void CSingleLayerCell::clearHeightMap()
|
||
{
|
||
delete _HeightMap;
|
||
_HeightMap = NULL;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A Multiple layer 16x16 cell (maximum 3 layers)
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CMultiLayerCell
|
||
: public CRootCell
|
||
{
|
||
protected:
|
||
class CCellLayer
|
||
{
|
||
friend class CMultiLayerCell; // for build features.
|
||
public:
|
||
CCellLinkage const& getCellLinkage(CMapPosition const& pos) const;
|
||
uint8 getTopology(CMapPosition const& pos) const;
|
||
I16x16Layer* getHeightMap() { return _HeightMap; }
|
||
|
||
private:
|
||
CCellLinkage& cellLinkage(CMapPosition const& pos);
|
||
|
||
private:
|
||
CCellLinkage _Layer[16*16];
|
||
uint8 _Topology[16*16];
|
||
I16x16Layer* _HeightMap;
|
||
};
|
||
|
||
public:
|
||
CMultiLayerCell(CWorldMap const& worldMapPtr);
|
||
virtual ~CMultiLayerCell();
|
||
|
||
CCellLinkage getCellLink(CWorldPosition const& wpos) const;
|
||
uint32 nbUsedSlots(CMapPosition const& pos) const;
|
||
sint32 maxUsedSlot(CMapPosition const& pos) const;
|
||
bool isSlotUsed(CMapPosition const& pos, CSlot const& slot) const;
|
||
uint getTopology(CWorldPosition const& wpos) const;
|
||
sint getHeight(CWorldPosition const& wpos) const;
|
||
|
||
virtual void serial(NLMISC::IStream& f);
|
||
|
||
void setLinks(CWorldPosition const& wpos, CCellLinkage links);
|
||
void setTopology(CWorldPosition const& wpos, uint topology);
|
||
void setHeightMap(CSlot const& slot, I16x16Layer* heightMap);
|
||
void clearHeightMap();
|
||
|
||
private:
|
||
// each layer is allocated in memory
|
||
// the 3 layers available
|
||
CCellLayer* _Layers[3];
|
||
};
|
||
|
||
inline
|
||
CCellLinkage const& CMultiLayerCell::CCellLayer::getCellLinkage(CMapPosition const& pos) const
|
||
{
|
||
return _Layer[pos.cellUnitFastIndex()]; //yCoord().getUnitId()][pos.xCoord().getUnitId()];
|
||
}
|
||
|
||
inline
|
||
uint8 CMultiLayerCell::CCellLayer::getTopology(CMapPosition const& pos) const
|
||
{
|
||
return _Topology[pos.cellUnitFastIndex()]; //yCoord().getUnitId()][pos.xCoord().getUnitId()];
|
||
}
|
||
|
||
inline
|
||
CCellLinkage& CMultiLayerCell::CCellLayer::cellLinkage(CMapPosition const& pos)
|
||
{
|
||
return _Layer[pos.cellUnitFastIndex()]; //yCoord().getUnitId()][pos.xCoord().getUnitId()];
|
||
}
|
||
|
||
inline
|
||
CMultiLayerCell::CMultiLayerCell(CWorldMap const& worldMapPtr)
|
||
: CRootCell(worldMapPtr)
|
||
{
|
||
_Layers[0] = NULL;
|
||
_Layers[1] = NULL;
|
||
_Layers[2] = NULL;
|
||
}
|
||
|
||
inline
|
||
CMultiLayerCell::~CMultiLayerCell()
|
||
{
|
||
delete [] _Layers[0];
|
||
delete [] _Layers[1];
|
||
delete [] _Layers[2];
|
||
}
|
||
|
||
inline
|
||
CCellLinkage CMultiLayerCell::getCellLink(CWorldPosition const& wpos) const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
CCellLayer* cellLayerPt=_Layers[wpos.slot()];
|
||
return (!cellLayerPt) ? CCellLinkage() : cellLayerPt->getCellLinkage(wpos);
|
||
}
|
||
|
||
inline
|
||
uint32 CMultiLayerCell::nbUsedSlots(CMapPosition const& pos) const
|
||
{
|
||
uint32 ns = 0;
|
||
for (uint32 slot=0; slot<3; ++slot)
|
||
{
|
||
CCellLayer* cellLayerPt=_Layers[slot];
|
||
if (cellLayerPt && cellLayerPt->cellLinkage(pos).used())
|
||
++ns;
|
||
}
|
||
return ns;
|
||
}
|
||
|
||
inline
|
||
sint32 CMultiLayerCell::maxUsedSlot(CMapPosition const& pos) const
|
||
{
|
||
sint32 maxs = -1;
|
||
for (uint32 slot=0; slot<3; ++slot)
|
||
{
|
||
CCellLayer* cellLayerPt=_Layers[slot];
|
||
if (cellLayerPt && cellLayerPt->cellLinkage(pos).used())
|
||
maxs = slot;
|
||
}
|
||
return maxs;
|
||
}
|
||
|
||
inline
|
||
bool CMultiLayerCell::isSlotUsed(CMapPosition const& pos, CSlot const& slot) const
|
||
{
|
||
if (!slot.isValid())
|
||
return false;
|
||
CCellLayer* cellLayerPt = _Layers[slot.slot()];
|
||
return (cellLayerPt && cellLayerPt->cellLinkage(pos).used());
|
||
}
|
||
|
||
inline
|
||
uint CMultiLayerCell::getTopology(CWorldPosition const& wpos) const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
CCellLayer* cellLayerPt = _Layers[wpos.slot()];
|
||
return (!cellLayerPt) ? 0 : cellLayerPt->getTopology(wpos);
|
||
}
|
||
|
||
inline
|
||
sint CMultiLayerCell::getHeight(CWorldPosition const& wpos) const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
CCellLayer* cellLayerPt = _Layers[wpos.slot()];
|
||
return (!cellLayerPt || !cellLayerPt->getHeightMap()) ? 0 : cellLayerPt->getHeightMap()->get(wpos.yCoord().getUnitId(), wpos.xCoord().getUnitId());
|
||
}
|
||
|
||
inline
|
||
void CMultiLayerCell::setLinks(CWorldPosition const& wpos, CCellLinkage links)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
CCellLayer* cellLayerPt = _Layers[wpos.slot()];
|
||
if (!cellLayerPt)
|
||
{
|
||
cellLayerPt = new CCellLayer();
|
||
_Layers[wpos.slot()] = cellLayerPt;
|
||
|
||
for (uint i=0; i<16*16; ++i)
|
||
cellLayerPt->_Topology[i] = 0;
|
||
cellLayerPt->_HeightMap = NULL;
|
||
}
|
||
#ifdef NL_DEBUG
|
||
nlassert(cellLayerPt);
|
||
#endif
|
||
cellLayerPt->cellLinkage(wpos)=links;
|
||
}
|
||
|
||
inline
|
||
void CMultiLayerCell::setTopology(CWorldPosition const& wpos, uint topology)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(topology < 256);
|
||
nlassert(wpos.isValid());
|
||
#endif
|
||
CCellLayer* cellLayerPt = _Layers[wpos.slot()];
|
||
|
||
#ifdef NL_DEBUG
|
||
nlassert(cellLayerPt);
|
||
#endif
|
||
cellLayerPt->_Topology[wpos.cellUnitFastIndex()]=(uint8)topology;
|
||
}
|
||
|
||
inline
|
||
void CMultiLayerCell::setHeightMap(CSlot const& slot, I16x16Layer* heightMap)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(slot.isValid());
|
||
#endif
|
||
CCellLayer* cellLayerPt = _Layers[slot.slot()];
|
||
|
||
#ifdef NL_DEBUG
|
||
nlassert(cellLayerPt);
|
||
#endif
|
||
if (cellLayerPt->_HeightMap)
|
||
delete cellLayerPt->_HeightMap;
|
||
cellLayerPt->_HeightMap = heightMap;
|
||
}
|
||
|
||
inline
|
||
void CMultiLayerCell::clearHeightMap()
|
||
{
|
||
for (CSlot i(0); i.isValid(); ++i)
|
||
{
|
||
CCellLayer* cellLayerPt = _Layers[i.slot()];
|
||
if (cellLayerPt)
|
||
{
|
||
delete cellLayerPt->_HeightMap;
|
||
cellLayerPt->_HeightMap=NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A CSuperCell of basically 16x16 CCells
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CSuperCell
|
||
{
|
||
public:
|
||
CSuperCell(CWorldMap const& worldMap);
|
||
virtual ~CSuperCell();
|
||
|
||
// get a const cell (might be NULL)
|
||
CRootCell const* getRootCellCst(CMapPosition const& pos) const;
|
||
// get a const cell (might be NULL)
|
||
CRootCell* getRootCell(CMapPosition const& pos);
|
||
|
||
void updateTopologyRef(CWorldMap* worldMap);
|
||
void countCells(uint& compute, uint& white, uint& simple, uint& multi, uint& other) const;
|
||
|
||
// set a cell
|
||
void setRootCell(CMapPosition const& pos, CRootCell* cell);
|
||
|
||
//
|
||
// compute cell selectors
|
||
//
|
||
|
||
// get a cell
|
||
CComputeCell* getComputeCell(CMapPosition const& pos);
|
||
// get a const cell
|
||
CComputeCell const* getComputeCell(CMapPosition const& pos) const;
|
||
|
||
// get a slot in a cell
|
||
CUnitSlot getUnitSlot(CWorldPosition const& wpos) const;
|
||
// get a slot in super cell
|
||
CUnitSlot& getUnitSlot(CWorldPosition const& wpos);
|
||
TCellUnit& getCellUnit(CMapPosition const& pos);
|
||
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
void markRootCell(uint32 const flag) const;
|
||
|
||
private:
|
||
// a super cell is composed of 16x16 pointers to cells, initially NULL
|
||
CRootCell* _Grid[16*16];
|
||
CWorldMap const& _WorldMap;
|
||
};
|
||
|
||
inline
|
||
CSuperCell::CSuperCell(CWorldMap const& worldMap)
|
||
: _WorldMap(worldMap)
|
||
{
|
||
for (uint i=0;i<16*16;i++)
|
||
_Grid[i] = NULL;
|
||
}
|
||
|
||
inline
|
||
CSuperCell::~CSuperCell()
|
||
{
|
||
for (uint i=0;i<16*16;i++)
|
||
if (_Grid[i])
|
||
delete _Grid[i];
|
||
}
|
||
|
||
inline
|
||
CRootCell const* CSuperCell::getRootCellCst(CMapPosition const& pos) const
|
||
{
|
||
return _Grid[pos.rootCellFastIndex()];
|
||
}
|
||
|
||
inline
|
||
CRootCell* CSuperCell::getRootCell(CMapPosition const& pos)
|
||
{
|
||
return _Grid[pos.rootCellFastIndex()];
|
||
}
|
||
|
||
inline
|
||
void CSuperCell::setRootCell(CMapPosition const& pos, CRootCell* cell)
|
||
{
|
||
CRootCell*& rootCell = _Grid[pos.rootCellFastIndex()];
|
||
if (rootCell==cell)
|
||
return;
|
||
delete rootCell;
|
||
rootCell = cell;
|
||
}
|
||
|
||
inline
|
||
CComputeCell* CSuperCell::getComputeCell(CMapPosition const& pos)
|
||
{
|
||
CRootCell*& rootCell = _Grid[pos.rootCellFastIndex()];
|
||
if (!rootCell)
|
||
rootCell = new CComputeCell(_WorldMap);
|
||
|
||
#ifdef NL_DEBUG
|
||
nlassert(rootCell);
|
||
nlassert(dynamic_cast<CComputeCell*>(rootCell));
|
||
#endif
|
||
return static_cast<CComputeCell*>(rootCell);
|
||
}
|
||
|
||
inline
|
||
CComputeCell const* CSuperCell::getComputeCell(CMapPosition const& pos) const
|
||
{
|
||
CRootCell const* const& rootCell = _Grid[pos.rootCellFastIndex()];
|
||
if (!rootCell)
|
||
return NULL;
|
||
#ifdef NL_DEBUG
|
||
nlassert(dynamic_cast<CComputeCell const*>(rootCell));
|
||
#endif
|
||
return static_cast<CComputeCell const*>(rootCell);
|
||
}
|
||
|
||
inline
|
||
CUnitSlot CSuperCell::getUnitSlot(CWorldPosition const& wpos) const
|
||
{
|
||
CComputeCell const* cell = getComputeCell(wpos);
|
||
return !cell ? CUnitSlot() : cell->getUnitSlotCst(wpos);
|
||
}
|
||
|
||
inline
|
||
CUnitSlot& CSuperCell::getUnitSlot(CWorldPosition const& wpos)
|
||
{
|
||
CComputeCell* cell = getComputeCell(wpos);
|
||
return cell->getUnitSlot(wpos);
|
||
}
|
||
|
||
inline
|
||
TCellUnit& CSuperCell::getCellUnit(CMapPosition const& pos)
|
||
{
|
||
CComputeCell* cell = getComputeCell(pos);
|
||
return cell->getCellUnit(pos);
|
||
}
|
||
|
||
inline
|
||
void CSuperCell::markRootCell(uint32 const flag) const
|
||
{
|
||
for (uint32 i=0; i<256; ++i)
|
||
{
|
||
if (_Grid[i])
|
||
_Grid[i]->setFlag(flag);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* The A* Path structure, computed by the WorldMap
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CAStarPath
|
||
{
|
||
friend class CWorldMap;
|
||
public:
|
||
std::vector<CTopology::TTopologyRef> const& topologiesPath() const { return _TopologiesPath; }
|
||
std::vector<CTopology::TTopologyRef>& topologiesPathForCalc() { return _TopologiesPath; }
|
||
|
||
CWorldPosition const& getStartPos() const { return _Start; }
|
||
void setStartPos(CWorldPosition const& pos) { _Start = pos; }
|
||
|
||
CWorldPosition const& getEndPos() const { return _End; }
|
||
void setEndPos(CWorldPosition const& pos) { _End = pos; }
|
||
|
||
private:
|
||
std::vector<CTopology::TTopologyRef> _TopologiesPath;
|
||
CWorldPosition _Start;
|
||
CWorldPosition _End;
|
||
};
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* The Inside A* Path structure, computed by the WorldMap
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
class CInsideAStarPath
|
||
{
|
||
friend class CWorldMap;
|
||
public:
|
||
CWorldPosition const& getStartPos() const { return _Start; }
|
||
void setStartPos(CWorldPosition const& pos) { _Start = pos; }
|
||
|
||
CWorldPosition const& getEndPos() const { return _End; }
|
||
void setEndPos(CWorldPosition const& pos) { _End = pos; }
|
||
std::vector<CDirection>& getStepPathForCalc() { return _StepPath; }
|
||
|
||
private:
|
||
CWorldPosition _Start;
|
||
CWorldPosition _End;
|
||
std::vector<CDirection> _StepPath;
|
||
};
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* A template Heap implementation
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
template <typename T, typename V>
|
||
class CHeap
|
||
{
|
||
public:
|
||
typedef std::pair<T, V> THeapNode;
|
||
|
||
public:
|
||
CHeap();
|
||
|
||
/// clear Heap
|
||
void clear() { _Heap.resize(1); }
|
||
|
||
/// test heap is empty or not
|
||
bool empty() const { return _Heap.size() <= 1; }
|
||
|
||
/// push a value in heap and sort it
|
||
void push(T key, V const& value);
|
||
|
||
/// pop the minimal value of the heap
|
||
V pop();
|
||
|
||
void backwardLeveling(uint index);
|
||
|
||
void forwardLeveling(uint index);
|
||
|
||
/// auto check of the internal heap state
|
||
void check();
|
||
|
||
uint32 size() { return _Heap.size(); }
|
||
|
||
std::vector<THeapNode>& heapAsVector() { return _Heap; }
|
||
|
||
private:
|
||
std::vector<THeapNode> _Heap;
|
||
};
|
||
|
||
template <typename T, typename V>
|
||
CHeap<T, V>::CHeap()
|
||
{
|
||
// node 0 unused (daniel's trick)
|
||
clear();
|
||
}
|
||
|
||
template <typename T, typename V>
|
||
void CHeap<T, V>::push(T key, V const& value)
|
||
{
|
||
_Heap.push_back(THeapNode(key, value));
|
||
|
||
backwardLeveling((uint)_Heap.size()-1);
|
||
}
|
||
|
||
template <typename T, typename V>
|
||
V CHeap<T, V>::pop()
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(_Heap.size() > 1);
|
||
#endif
|
||
|
||
// return best value
|
||
V ret = _Heap[1].second;
|
||
|
||
// if only 1 node in heap, pop it and leave
|
||
if (_Heap.size() == 2)
|
||
{
|
||
_Heap.pop_back();
|
||
return ret;
|
||
}
|
||
|
||
// for more than 1 object, copy last at top and pop last
|
||
_Heap[1] = _Heap.back();
|
||
_Heap.pop_back();
|
||
|
||
forwardLeveling (1);
|
||
return ret;
|
||
}
|
||
|
||
template <typename T, typename V>
|
||
void CHeap<T, V>::backwardLeveling(uint index)
|
||
{
|
||
while (index != 1 && _Heap[index].first < _Heap[index/2].first)
|
||
{
|
||
swap(_Heap[index], _Heap[index/2]);
|
||
index /= 2;
|
||
}
|
||
}
|
||
|
||
template <typename T, typename V>
|
||
void CHeap<T, V>::forwardLeveling(uint index)
|
||
{
|
||
while (true)
|
||
{
|
||
uint min_index = 2*index;
|
||
|
||
// if object has no child, leave
|
||
if (min_index > _Heap.size()-1)
|
||
break;
|
||
|
||
// choose left or right child
|
||
if (min_index+1 <= _Heap.size()-1 && _Heap[min_index].first>_Heap[min_index+1].first)
|
||
++min_index;
|
||
|
||
// if swap needed, swap and step one more, else leave
|
||
if (_Heap[index].first > _Heap[min_index].first)
|
||
{
|
||
swap(_Heap[index], _Heap[min_index]);
|
||
index = min_index;
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
template <typename T, typename V>
|
||
void CHeap<T, V>::check()
|
||
{
|
||
for (uint index=1; index<=_Heap.size()-1; ++index)
|
||
{
|
||
if (2*index <= _Heap.size()-1)
|
||
nlassert(_Heap[index].first <= _Heap[2*index].first);
|
||
if (2*index+1 <= _Heap.size()-1)
|
||
nlassert(_Heap[index].first <= _Heap[2*index+1].first);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
/**
|
||
* The world mapping
|
||
* \author Benjamin Legros
|
||
* \author Nevrax France
|
||
* \date 2003
|
||
*/
|
||
|
||
class CWorldMap
|
||
{
|
||
friend class RYPACSCRUNCH::CPacsCruncher;
|
||
friend class CWorldPosition;
|
||
friend class CTopology::CNeighbourLink;
|
||
public:
|
||
CWorldMap();
|
||
~CWorldMap();
|
||
|
||
// serial -- beware, this method merges, use clear() before to load only one world map
|
||
void serial(NLMISC::IStream& f);
|
||
|
||
/// \name User Interface, path finding and complex moves
|
||
// @{
|
||
/// Finds an A* path
|
||
bool findAStarPath(CWorldPosition const& start, CWorldPosition const& end, std::vector<CTopology::TTopologyRef>& path, TAStarFlag denyflags = Nothing) const;
|
||
|
||
/// Finds an A* path
|
||
bool findAStarPath(CTopology::TTopologyId const& start, CTopology::TTopologyId const& end, CAStarPath& path, TAStarFlag denyflags = Nothing) const;
|
||
|
||
/// Finds an A* inside a topoly
|
||
bool findInsideAStarPath(CWorldPosition const& start, CWorldPosition const& end, std::vector<CDirection>& stepPath, TAStarFlag denyflags = Nothing) const;
|
||
|
||
/// Moves to given topology, returns false if failed
|
||
bool moveTowards(CWorldPosition& pos, CTopology::TTopologyRef const& topology) const;
|
||
|
||
/// Moves according a to a given path, returns false if failed
|
||
bool move(CWorldPosition& pos, CAStarPath& path, uint& currentstep) const;
|
||
|
||
/// Moves from a position to another
|
||
bool move(CWorldPosition& pos, CMapPosition const& end, TAStarFlag const denyFlags) const;
|
||
// @}
|
||
|
||
bool customCheckDiagMove(CWorldPosition const& pos, CDirection const& direction, RYAI_MAP_CRUNCH::TAStarFlag denyFlags) const;
|
||
|
||
// clean
|
||
void clear();
|
||
|
||
void setFlagOnPosAndRadius(CMapPosition const& pos, float radius, uint32 flag);
|
||
|
||
// to remove.
|
||
CNeighbourhood neighbours(CWorldPosition const& wpos) const;
|
||
|
||
/// Moves in neighbourhood
|
||
bool move(CWorldPosition& pos, CDirection const& direction) const;
|
||
|
||
/// Moves in neighbourhood (corner moves don't avoid collision)
|
||
bool moveSecure(CWorldPosition& pos, CDirection const& direction, uint16 maskFlags = 0xffff) const;
|
||
|
||
/// Moves in neighbourhood with diag test on both sides
|
||
bool moveDiagTestBothSide(CWorldPosition& pos, CDirection const& direction) const;
|
||
|
||
CTopology::TTopologyId getTopologyId(CWorldPosition const& wpos) const;
|
||
|
||
// LastRemoved
|
||
CTopology const& getTopologyNode(CTopology::TTopologyId const& id) const;
|
||
|
||
CTopology& getTopologyNode(CTopology::TTopologyId const& id);
|
||
|
||
CGridDirectionLayer const* getGridDirectionLayer(CWorldPosition const& pos, CTopology::TTopologyRef const& topologyRef) const;
|
||
|
||
/// Get CWorldPosition from a CMapPosition and a CSlot
|
||
CWorldPosition getWorldPosition(CMapPosition const& mapPos, CSlot const& slot) const;
|
||
|
||
/**
|
||
* Get CWorldPosition from a CMapPosition and a TLevel
|
||
* Assumes that 0 is the highest level at the given CMapPosition, and greater the level is, lower the height is.
|
||
*/
|
||
CWorldPosition getWorldPosition(CMapPosition const& mapPos, TLevel level) const;
|
||
|
||
// do not initialise a bot with the position & the world position (or u must assume that pos have no fraction).
|
||
bool setWorldPosition(AITYPES::TVerticalPos verticalPos, CWorldPosition& wpos, CAIVector const& pos, CRootCell const* originCell = NULL) const;
|
||
|
||
// Alternate setWorldPosition(), with real z instead of TVerticalPos, in millimeters
|
||
bool setWorldPosition(sint32 z, CWorldPosition& wpos, CAIVector const& pos, CRootCell const* originCell = NULL) const;
|
||
// Double version isn't tested !!! Verify it's the same than above sint32 version !
|
||
bool setWorldPosition(double z, CWorldPosition& wpos, CAIVector const& pos, CRootCell const* originCell = NULL) const;
|
||
|
||
CTopology::TTopologyRef getTopologyRef(CTopology::TTopologyId const& id) const;
|
||
|
||
void buildMasterTopo(bool allowWater, bool allowNogo);
|
||
|
||
// checks motion layers
|
||
void checkMotionLayer();
|
||
|
||
void countSuperTopo();
|
||
|
||
CRootCell const* getRootCellCst(CMapPosition const& pos) const;
|
||
|
||
CSuperCell const* getSuperCellCst(CMapPosition const& pos) const;
|
||
|
||
void getBounds(CMapPosition& min, CMapPosition& max);
|
||
|
||
CWorldPosition getSafeWorldPosition(CMapPosition const& mapPos, CSlot const& slot) const;
|
||
|
||
protected:
|
||
CWorldPosition getWorldPositionGeneration(CMapPosition const& mapPos, CSlot const& slot) const;
|
||
|
||
|
||
/// Get a world position from a vector position
|
||
template <class T>
|
||
CWorldPosition getWorldPosition(T const& pos) const
|
||
{
|
||
CSlot slot;
|
||
CMapPosition const mapPos(pos);
|
||
|
||
CRootCell const* cell = getRootCellCst(mapPos);
|
||
if (cell)
|
||
{
|
||
double bd = 1.0e10;
|
||
|
||
// find best slot
|
||
for (uint32 s=0; s<3; ++s)
|
||
{
|
||
CSlot const sslot = CSlot(s);
|
||
if (!cell->isSlotUsed(mapPos, sslot))
|
||
continue;
|
||
double const sh = cell->getHeight(CWorldPosition(cell,mapPos,sslot))*2.0 + 1.0;
|
||
if (fabs(sh) < bd)
|
||
{
|
||
bd = fabs(sh);
|
||
slot=sslot;
|
||
}
|
||
}
|
||
}
|
||
return CWorldPosition(cell,mapPos,slot);
|
||
}
|
||
|
||
|
||
// only for generation.
|
||
CSuperCell* getSuperCell(CMapPosition const& pos);
|
||
|
||
CComputeCell* getComputeCell(CMapPosition const& pos);
|
||
|
||
CRootCell* getRootCell(CMapPosition const& pos);
|
||
|
||
bool exist(CMapPosition const& pos) const;
|
||
|
||
uint32 nbUsedSlots(CMapPosition const& pos) const;
|
||
|
||
sint32 maxUsedSlot(CMapPosition const& pos) const;
|
||
|
||
bool isSlotUsed(CMapPosition const& pos, CSlot slot) const;
|
||
|
||
// used in build process.
|
||
uint getTopology(CWorldPosition const& wpos) const;
|
||
|
||
void countCells(uint& compute, uint& white, uint& simple, uint& multi, uint& other) const;
|
||
|
||
// mutators
|
||
void setRootCell(CMapPosition const& pos, CRootCell* cell);
|
||
|
||
// clear height map
|
||
void clearHeightMap();
|
||
|
||
//
|
||
// compute cell selectors
|
||
//
|
||
|
||
TCellUnit& getCellUnit(CMapPosition const& pos);
|
||
|
||
CUnitSlot& getUnitSlot(CWorldPosition const& wpos);
|
||
|
||
CComputeCell const* getComputeCellCst(CMapPosition const& pos) const;
|
||
|
||
void resetUnitSlotNLink(CWorldPosition const& wpos) { getUnitSlot(wpos).cellLink().setNSlot(CSlot()); }
|
||
void resetUnitSlotSLink(CWorldPosition const& wpos) { getUnitSlot(wpos).cellLink().setSSlot(CSlot()); }
|
||
void resetUnitSlotWLink(CWorldPosition const& wpos) { getUnitSlot(wpos).cellLink().setWSlot(CSlot()); }
|
||
void resetUnitSlotELink(CWorldPosition const& wpos) { getUnitSlot(wpos).cellLink().setESlot(CSlot()); }
|
||
|
||
void resetUnitSlot(CWorldPosition const& wpos);
|
||
|
||
private:
|
||
CSuperCell* _GridFastAccess[256*256];
|
||
|
||
public:
|
||
/// \name Path finding related error handling
|
||
// @{
|
||
enum TFindAStarPathReason
|
||
{
|
||
FASPR_NO_REASON = -1,
|
||
FASPR_NO_ERROR,
|
||
FASPR_INVALID_START_POS,
|
||
FASPR_INVALID_END_POS,
|
||
FASPR_INVALID_START_TOPO,
|
||
FASPR_INVALID_END_TOPO,
|
||
FASPR_INCOMPATIBLE_POSITIONS,
|
||
FASPR_NOT_FOUND
|
||
};
|
||
mutable TFindAStarPathReason _LastFASPReason;
|
||
static std::string toString(TFindAStarPathReason reason);
|
||
enum TFindInsideAStarPathReason
|
||
{
|
||
FIASPR_NO_REASON = -1,
|
||
FIASPR_NO_ERROR,
|
||
FIASPR_INVALID_START_POS,
|
||
FIASPR_INVALID_END_POS,
|
||
FIASPR_DIFFERENT_TOPO,
|
||
FIASPR_NOT_FOUND
|
||
};
|
||
mutable TFindInsideAStarPathReason _LastFIASPReason;
|
||
static std::string toString(TFindInsideAStarPathReason reason);
|
||
// @}
|
||
};
|
||
|
||
inline
|
||
CWorldPosition::CWorldPosition(const CRootCell *cell, const CMapPosition &pos, const CSlot &slot) : _RootCell(cell), CMapPosition(pos), CSlot(slot)
|
||
{
|
||
_cellLinkage=_RootCell->getCellLink(*this);
|
||
}
|
||
|
||
inline
|
||
CWorldPosition::CWorldPosition(const CRootCell *cell, const CMapPosition &pos, const CSlot &slot,bool generationOnly) : _RootCell(cell), CMapPosition(pos), CSlot(slot)
|
||
{
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldPosition::getPosS() const
|
||
{
|
||
CWorldPosition wp(*this);
|
||
wp.stepS();
|
||
return wp;
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldPosition::getPosN() const
|
||
{
|
||
CWorldPosition wp(*this);
|
||
wp.stepN();
|
||
return wp;
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldPosition::getPosE() const
|
||
{
|
||
CWorldPosition wp(*this);
|
||
wp.stepE();
|
||
return wp;
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldPosition::getPosW() const
|
||
{
|
||
CWorldPosition wp(*this);
|
||
wp.stepW();
|
||
return wp;
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::setPosS(CWorldPosition& pos) const
|
||
{
|
||
pos = *this;
|
||
pos.stepS();
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::setPosN(CWorldPosition& pos) const
|
||
{
|
||
pos = *this;
|
||
pos.stepN();
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::setPosE(CWorldPosition& pos) const
|
||
{
|
||
pos = *this;
|
||
pos.stepE();
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::setPosW(CWorldPosition& pos) const
|
||
{
|
||
pos = *this;
|
||
pos.stepW();
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::stepS()
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(_RootCell);
|
||
#endif
|
||
setSlot(_cellLinkage.SSlot());
|
||
#ifdef NL_DEBUG
|
||
nlassert(CSlot::isValid());
|
||
#endif
|
||
|
||
if (CMapPosition::stepS()) // check if we have to recalculate the RootCell ..
|
||
{
|
||
_RootCell = getRootCell()->getWorldMapPtr().getRootCellCst(*this); // obtain the new _RootCell pointer
|
||
}
|
||
_cellLinkage = _RootCell->getCellLink(*this);
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::stepN()
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(_RootCell);
|
||
#endif
|
||
setSlot(_cellLinkage.NSlot());
|
||
#ifdef NL_DEBUG
|
||
nlassert(CSlot::isValid());
|
||
#endif
|
||
|
||
if (CMapPosition::stepN()) // check if we have to recalculate the RootCell ..
|
||
{
|
||
_RootCell = getRootCell()->getWorldMapPtr().getRootCellCst(*this); // obtain the new _RootCell pointer
|
||
}
|
||
_cellLinkage = _RootCell->getCellLink(*this);
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::stepE()
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(_RootCell);
|
||
#endif
|
||
setSlot(_cellLinkage.ESlot());
|
||
#ifdef NL_DEBUG
|
||
nlassert(CSlot::isValid());
|
||
#endif
|
||
|
||
if (CMapPosition::stepE()) // check if we have to recalculate the RootCell ..
|
||
{
|
||
_RootCell = getRootCell()->getWorldMapPtr().getRootCellCst(*this); // obtain the new _RootCell pointer
|
||
}
|
||
_cellLinkage = _RootCell->getCellLink(*this);
|
||
}
|
||
|
||
inline
|
||
void CWorldPosition::stepW()
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(_RootCell);
|
||
#endif
|
||
setSlot(_cellLinkage.WSlot());
|
||
#ifdef NL_DEBUG
|
||
nlassert(CSlot::isValid());
|
||
#endif
|
||
|
||
if (CMapPosition::stepW()) // check if we have to recalculate the RootCell ..
|
||
{
|
||
_RootCell = getRootCell()->getWorldMapPtr().getRootCellCst(*this); // obtain the new _RootCell pointer
|
||
}
|
||
_cellLinkage = _RootCell->getCellLink(*this);
|
||
}
|
||
|
||
inline
|
||
bool CWorldPosition::moveS()
|
||
{
|
||
if (getCellLinkage().isSSlotValid())
|
||
{
|
||
stepS();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
inline
|
||
bool CWorldPosition::moveN()
|
||
{
|
||
if (getCellLinkage().isNSlotValid())
|
||
{
|
||
stepN();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
inline
|
||
bool CWorldPosition::moveE()
|
||
{
|
||
if (getCellLinkage().isESlotValid())
|
||
{
|
||
stepE();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
inline
|
||
bool CWorldPosition::moveW()
|
||
{
|
||
if (getCellLinkage().isWSlotValid())
|
||
{
|
||
stepW();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
inline
|
||
NLMISC::CVectorD CWorldPosition::getPosition() const
|
||
{
|
||
NLMISC::CVectorD ret = toVectorD();
|
||
CRootCell const* cell = getRootCell();
|
||
if (cell)
|
||
ret.z = cell->getHeight(*this)*2.0 + 1.0;
|
||
return ret;
|
||
}
|
||
|
||
inline
|
||
sint32 CWorldPosition::getMetricHeight() const
|
||
{
|
||
if (_RootCell)
|
||
return _RootCell->getMetricHeight(*this);
|
||
return 0;
|
||
}
|
||
|
||
inline
|
||
CTopology const& CTopology::TTopologyRef::getCstTopologyNode() const
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(_RootCell);
|
||
#endif
|
||
return _RootCell->getCstTopologyNode(getTopologyIndex());
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef::TTopologyRef(CWorldPosition const& pos, CRootCell const* rootCell)
|
||
: TTopologyId(pos, rootCell->getTopology(pos))
|
||
, _RootCell(rootCell)
|
||
{
|
||
#ifdef NL_DEBUG
|
||
nlassert(rootCell);
|
||
#endif
|
||
// TESTTOREMOVE TODO
|
||
#if !FINAL_VERSION
|
||
nlassert(&_RootCell->getCstTopologyNode(getTopologyIndex())!=NULL);
|
||
#endif
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef::TTopologyRef(CWorldPosition const& pos)
|
||
: TTopologyId(pos, pos.getRootCell()->getTopology(pos))
|
||
, _RootCell(pos.getRootCell())
|
||
{
|
||
// TESTTOREMOVE TODO
|
||
#if !FINAL_VERSION
|
||
nlassert(&_RootCell->getCstTopologyNode(getTopologyIndex())!=NULL);
|
||
#endif
|
||
}
|
||
|
||
inline
|
||
void CTopology::CNeighbourLink::updateTopologyRef(CWorldMap* worldMapPtr)
|
||
{
|
||
_Ref.setRootCell(worldMapPtr->getRootCell(_Ref.getMapPosition()));
|
||
// TESTTOREMOVE TODO
|
||
#if !FINAL_VERSION
|
||
nlassert(&_Ref.getCstTopologyNode()!=NULL);
|
||
#endif
|
||
}
|
||
|
||
inline
|
||
CWorldMap::CWorldMap()
|
||
{
|
||
for (uint i=0; i<65536; ++i)
|
||
_GridFastAccess[i]=NULL;
|
||
}
|
||
|
||
inline
|
||
CWorldMap::~CWorldMap()
|
||
{
|
||
for (uint i=0; i<65536; ++i)
|
||
if (_GridFastAccess[i])
|
||
delete _GridFastAccess[i];
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyId CWorldMap::getTopologyId(CWorldPosition const& wpos) const
|
||
{
|
||
CRootCell const* cell = getRootCellCst(wpos);
|
||
return !cell ? CTopology::TTopologyId() : CTopology::TTopologyId(wpos, cell->getTopology(wpos));
|
||
}
|
||
|
||
inline
|
||
CTopology const& CWorldMap::getTopologyNode(CTopology::TTopologyId const& id) const
|
||
{
|
||
CMapPosition pos = id.getMapPosition();
|
||
uint topo = id.getTopologyIndex();
|
||
|
||
CRootCell const* cell = getRootCellCst(pos);
|
||
#ifdef NL_DEBUG
|
||
nlassert(cell);
|
||
#endif
|
||
return cell->getCstTopologyNode(topo);
|
||
}
|
||
|
||
inline
|
||
CTopology& CWorldMap::getTopologyNode(CTopology::TTopologyId const& id)
|
||
{
|
||
CMapPosition pos = id.getMapPosition();
|
||
uint topo = id.getTopologyIndex();
|
||
|
||
CRootCell* cell = getRootCell(pos);
|
||
#ifdef NL_DEBUG
|
||
nlassert(cell);
|
||
#endif
|
||
return cell->getTopologyNode(topo);
|
||
}
|
||
|
||
inline
|
||
CGridDirectionLayer const* CWorldMap::getGridDirectionLayer(CWorldPosition const& pos, CTopology::TTopologyRef const& topologyRef) const
|
||
{
|
||
if (!pos.isValid())
|
||
return NULL;
|
||
|
||
CMapPosition tpos = topologyRef.getMapPosition();
|
||
|
||
sint dx = pos.xCoord().getFullCellId()-tpos.xCoord().getFullCellId();
|
||
sint dy = pos.yCoord().getFullCellId()-tpos.yCoord().getFullCellId();
|
||
|
||
if (abs(dx) > 1 || abs(dy) > 1)
|
||
return NULL;
|
||
|
||
CTopology const& node = topologyRef.getCstTopologyNode();
|
||
|
||
if (!node.DirectionMap)
|
||
return NULL;
|
||
|
||
CDirectionLayer* directionLayer = node.DirectionMap->Layers[pos.slot()];
|
||
if (!directionLayer)
|
||
return NULL;
|
||
|
||
return directionLayer->getGridLayer(dy+1,dx+1);
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldMap::getWorldPosition(CMapPosition const& mapPos, CSlot const& slot) const
|
||
{
|
||
return CWorldPosition(getRootCellCst(mapPos), mapPos, slot);
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldMap::getWorldPosition(CMapPosition const& mapPos, TLevel level) const
|
||
{
|
||
CRootCell const* cell = getRootCellCst(mapPos);
|
||
|
||
std::vector<sint32> slots;
|
||
slots.reserve(4);
|
||
|
||
// go through all slots and get their height
|
||
for (uint s=0; s<3; ++s)
|
||
{
|
||
CSlot slot(s);
|
||
|
||
if (!cell->isSlotUsed(mapPos, slot))
|
||
continue;
|
||
|
||
CWorldPosition wPos = CWorldPosition(cell, mapPos, slot);
|
||
slots.push_back((cell->getHeight(wPos) << 2) + s);
|
||
}
|
||
|
||
// sort them, from the lowest to the heightest
|
||
std::sort(slots.begin(), slots.end());
|
||
|
||
// get heightest slot
|
||
level = (RYAI_MAP_CRUNCH::TLevel)(slots.size()-1) - level;
|
||
|
||
// if slot exists, return it or invalid position
|
||
return (level < 0 && level >= (sint)slots.size()) ? CWorldPosition() : CWorldPosition(cell, mapPos, CSlot(slots[level]&3));
|
||
}
|
||
|
||
inline
|
||
bool CWorldMap::setWorldPosition(AITYPES::TVerticalPos verticalPos, CWorldPosition& wpos, CAIVector const& pos, CRootCell const* originCell) const
|
||
{
|
||
CSlot slot;
|
||
CMapPosition const mapPos(pos);
|
||
|
||
CRootCell const* cell = originCell ? originCell : getRootCellCst(mapPos);
|
||
if (!cell)
|
||
{
|
||
wpos = CWorldPosition(cell, mapPos, slot, true);
|
||
// addon (not agree but no choice).
|
||
return false;
|
||
}
|
||
|
||
std::map<double, CSlot> orderedSlots;
|
||
// find best slot
|
||
for (uint32 s=0; s<3; ++s)
|
||
{
|
||
if (!cell->isSlotUsed(mapPos, CSlot(s)))
|
||
continue;
|
||
|
||
CSlot const sslot = CSlot(s);
|
||
double const sh = cell->getHeight(CWorldPosition(cell,mapPos,sslot));
|
||
orderedSlots.insert(std::make_pair(sh, sslot));
|
||
}
|
||
|
||
if (!orderedSlots.empty())
|
||
{
|
||
if (verticalPos == AITYPES::vp_auto)
|
||
{
|
||
double h = orderedSlots.rbegin()->first;
|
||
slot = orderedSlots.rbegin()->second;
|
||
}
|
||
else if (verticalPos == AITYPES::vp_upper)
|
||
{
|
||
double h = orderedSlots.rbegin()->first;
|
||
slot = orderedSlots.rbegin()->second;
|
||
}
|
||
else if (verticalPos == AITYPES::vp_lower)
|
||
{
|
||
double h = orderedSlots.begin()->first;
|
||
slot = orderedSlots.begin()->second;
|
||
}
|
||
else if (verticalPos == AITYPES::vp_middle)
|
||
{
|
||
if (orderedSlots.size() > 1)
|
||
{
|
||
orderedSlots.erase(orderedSlots.rbegin()->first);
|
||
double h = orderedSlots.rbegin()->first;
|
||
slot = orderedSlots.rbegin()->second;
|
||
}
|
||
else
|
||
{
|
||
double h = orderedSlots.begin()->first;
|
||
slot = orderedSlots.begin()->second;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
nlwarning("invalid vertical pos type !");
|
||
}
|
||
}
|
||
|
||
if (!slot.isValid())
|
||
{
|
||
wpos = CWorldPosition(cell,mapPos,slot,true);
|
||
return false;
|
||
}
|
||
|
||
wpos = CWorldPosition(cell,mapPos,slot);
|
||
return true;
|
||
}
|
||
|
||
inline
|
||
CTopology::TTopologyRef CWorldMap::getTopologyRef(CTopology::TTopologyId const& id) const
|
||
{
|
||
return CTopology::TTopologyRef(id, const_cast<CRootCell*>(getRootCellCst(id.getMapPosition())));
|
||
}
|
||
|
||
inline
|
||
CRootCell const* CWorldMap::getRootCellCst(CMapPosition const& pos) const
|
||
{
|
||
CSuperCell const* scell = getSuperCellCst(pos);
|
||
return !scell ? NULL : scell->getRootCellCst(pos);
|
||
}
|
||
|
||
inline
|
||
CSuperCell const* CWorldMap::getSuperCellCst(CMapPosition const& pos) const
|
||
{
|
||
return _GridFastAccess[pos.superCellFastIndex()];
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldMap::getWorldPositionGeneration(CMapPosition const& mapPos, CSlot const& slot) const
|
||
{
|
||
return CWorldPosition(getRootCellCst(mapPos),mapPos,slot,true); // without assuring cellLink is valid .. :(
|
||
}
|
||
|
||
inline
|
||
CWorldPosition CWorldMap::getSafeWorldPosition(CMapPosition const& mapPos, CSlot const& slot) const
|
||
{
|
||
CRootCell const* cell = getRootCellCst(mapPos);
|
||
return (cell && cell->isSlotUsed(mapPos, slot)) ? CWorldPosition(getRootCellCst(mapPos),mapPos,slot) : CWorldPosition(); // without assuring cellLink is valid .. :(
|
||
}
|
||
|
||
inline
|
||
CSuperCell* CWorldMap::getSuperCell(CMapPosition const& pos)
|
||
{
|
||
CSuperCell* superCellPtr = _GridFastAccess[pos.superCellFastIndex()];
|
||
|
||
if (!superCellPtr)
|
||
_GridFastAccess[pos.superCellFastIndex()] = superCellPtr=new CSuperCell(*this);
|
||
|
||
#ifdef NL_DEBUG
|
||
nlassert(superCellPtr);
|
||
#endif
|
||
return superCellPtr;
|
||
}
|
||
|
||
inline
|
||
CComputeCell* CWorldMap::getComputeCell(CMapPosition const& pos)
|
||
{
|
||
return getSuperCell(pos)->getComputeCell(pos);
|
||
}
|
||
|
||
inline
|
||
CRootCell* CWorldMap::getRootCell(CMapPosition const& pos)
|
||
{
|
||
CSuperCell* scell = getSuperCell(pos);
|
||
return !scell ? NULL : scell->getRootCell(pos);
|
||
}
|
||
|
||
inline
|
||
bool CWorldMap::exist(CMapPosition const& pos) const
|
||
{
|
||
return getRootCellCst(pos)!=NULL;
|
||
}
|
||
|
||
inline
|
||
uint32 CWorldMap::nbUsedSlots(CMapPosition const& pos) const
|
||
{
|
||
CRootCell const* cell = getRootCellCst(pos);
|
||
return !cell ? 0:cell->nbUsedSlots(pos);
|
||
}
|
||
|
||
inline
|
||
sint32 CWorldMap::maxUsedSlot(CMapPosition const& pos) const
|
||
{
|
||
CRootCell const* cell = getRootCellCst(pos);
|
||
return !cell ? -1 : cell->maxUsedSlot(pos);
|
||
}
|
||
|
||
inline
|
||
bool CWorldMap::isSlotUsed(CMapPosition const& pos, CSlot slot) const
|
||
{
|
||
CRootCell const* cell = getRootCellCst(pos);
|
||
return !cell ? false : cell->isSlotUsed(pos, slot);
|
||
}
|
||
|
||
inline
|
||
uint CWorldMap::getTopology(CWorldPosition const& wpos) const
|
||
{
|
||
CRootCell const* cell = wpos.getRootCell(); //getRootCellCst(wpos);
|
||
return !cell ? 0 : cell->getTopology(wpos);
|
||
}
|
||
|
||
inline
|
||
void CWorldMap::setRootCell(CMapPosition const& pos, CRootCell* cell)
|
||
{
|
||
getSuperCell(pos)->setRootCell(pos, cell);
|
||
}
|
||
|
||
inline
|
||
TCellUnit& CWorldMap::getCellUnit(CMapPosition const& pos)
|
||
{
|
||
return getComputeCell(pos)->getCellUnit(pos);
|
||
}
|
||
|
||
inline
|
||
CUnitSlot& CWorldMap::getUnitSlot(CWorldPosition const& wpos)
|
||
{
|
||
return getComputeCell(wpos)->getUnitSlot(wpos);
|
||
}
|
||
|
||
inline
|
||
CComputeCell const* CWorldMap::getComputeCellCst(CMapPosition const& pos) const
|
||
{
|
||
CSuperCell const* scell = getSuperCellCst(pos);
|
||
return !scell ? NULL : scell->getComputeCell(pos);
|
||
}
|
||
|
||
inline
|
||
void CWorldMap::resetUnitSlot(CWorldPosition const& wpos)
|
||
{
|
||
CUnitSlot& us = getUnitSlot(wpos);
|
||
|
||
if (us.getCellLink().isNSlotValid()) resetUnitSlotSLink(wpos.getPosN());
|
||
if (us.getCellLink().isSSlotValid()) resetUnitSlotNLink(wpos.getPosS());
|
||
if (us.getCellLink().isWSlotValid()) resetUnitSlotELink(wpos.getPosW());
|
||
if (us.getCellLink().isESlotValid()) resetUnitSlotWLink(wpos.getPosE());
|
||
|
||
us.reset();
|
||
}
|
||
|
||
inline
|
||
std::string CWorldMap::toString(TFindAStarPathReason reason)
|
||
{
|
||
switch (reason)
|
||
{
|
||
case FASPR_NO_ERROR:
|
||
return "FASPR_NO_ERROR";
|
||
case FASPR_INVALID_START_POS:
|
||
return "FASPR_INVALID_START_POS";
|
||
case FASPR_INVALID_END_POS:
|
||
return "FASPR_INVALID_END_POS";
|
||
case FASPR_INVALID_START_TOPO:
|
||
return "FASPR_INVALID_START_TOPO";
|
||
case FASPR_INVALID_END_TOPO:
|
||
return "FASPR_INVALID_END_TOPO";
|
||
case FASPR_INCOMPATIBLE_POSITIONS:
|
||
return "FASPR_INCOMPATIBLE_POSITIONS";
|
||
case FASPR_NOT_FOUND:
|
||
return "FIASPR_NOT_FOUND";
|
||
default:
|
||
return "UnknownReason(" + NLMISC::toString((int)reason) + ")";
|
||
}
|
||
}
|
||
|
||
inline
|
||
std::string CWorldMap::toString(TFindInsideAStarPathReason reason)
|
||
{
|
||
switch (reason)
|
||
{
|
||
case FIASPR_NO_ERROR:
|
||
return "FIASPR_NO_ERROR";
|
||
case FIASPR_INVALID_START_POS:
|
||
return "FIASPR_INVALID_START_POS";
|
||
case FIASPR_INVALID_END_POS:
|
||
return "FIASPR_INVALID_END_POS";
|
||
case FIASPR_DIFFERENT_TOPO:
|
||
return "FIASPR_DIFFERENT_TOPO";
|
||
case FIASPR_NOT_FOUND:
|
||
return "FIASPR_NOT_FOUND";
|
||
default:
|
||
return "UnknownReason(" + NLMISC::toString((int)reason) + ")";
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
class CTimeEstimator
|
||
{
|
||
public:
|
||
CTimeEstimator(uint total);
|
||
|
||
void step(char const* str);
|
||
|
||
private:
|
||
NLMISC::TTime _StartTime;
|
||
NLMISC::TTime _LastTime;
|
||
|
||
uint _TotalCounter;
|
||
uint _CurrentCounter;
|
||
uint _LastCounter;
|
||
|
||
double _AverageSpeed;
|
||
|
||
std::string secToString(sint sec);
|
||
};
|
||
|
||
inline
|
||
CTimeEstimator::CTimeEstimator(uint total)
|
||
: _TotalCounter(total)
|
||
, _CurrentCounter(0)
|
||
, _LastCounter(0)
|
||
, _AverageSpeed(-1.0)
|
||
{
|
||
_StartTime = NLMISC::CTime::getLocalTime();
|
||
_LastTime = _StartTime;
|
||
}
|
||
|
||
inline
|
||
void CTimeEstimator::step(char const* str)
|
||
{
|
||
++_CurrentCounter;
|
||
|
||
NLMISC::TTime currentTime = NLMISC::CTime::getLocalTime();
|
||
|
||
if (currentTime-_LastTime > 2000)
|
||
{
|
||
NLMISC::TTime dt = currentTime-_LastTime;
|
||
double speed = 1000.0*(_CurrentCounter-_LastCounter)/dt;
|
||
|
||
_AverageSpeed = (_AverageSpeed < 0.0 ? speed : _AverageSpeed*0.98 + speed*0.02);
|
||
|
||
uint remaining = _TotalCounter-_CurrentCounter;
|
||
|
||
NLMISC::TTime ellapsedTime = currentTime-_StartTime;
|
||
NLMISC::TTime remainingTime = (NLMISC::TTime)(remaining*1000/_AverageSpeed);
|
||
|
||
double percent = 100.0*_CurrentCounter/_TotalCounter;
|
||
uint maxpercent = (percent > 100.0 ? 100 : (uint)percent);
|
||
uint linesize = maxpercent/5;
|
||
|
||
nlinfo("%s: %.1f%% [ellapsed:%s, togo:%s, total:%s]", str, percent, secToString((uint)(ellapsedTime/1000)).c_str(), secToString((uint)(remainingTime/1000)).c_str(), secToString((uint)((remainingTime+ellapsedTime)/1000)).c_str());
|
||
|
||
_LastCounter = _CurrentCounter;
|
||
_LastTime = currentTime;
|
||
}
|
||
}
|
||
|
||
inline
|
||
std::string CTimeEstimator::secToString(sint sec)
|
||
{
|
||
return NLMISC::toString(sec/60)+"m"+NLMISC::toString(sec%60)+"s";
|
||
}
|
||
|
||
#endif
|