2010-05-06 00:08:41 +00:00
// 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/>.
# include "stdpch.h"
# include "nel/misc/string_mapper.h"
# include "nel/net/service.h"
# include "algorithm"
# include "continent.h"
# include "ai_instance.h"
# include "ai_mgr.h"
# include "ai_grp_fauna.h"
# include "ai_mgr_fauna.h"
# include "ai_grp_npc.h"
# include "ai_mgr_npc.h"
# include "ai_bot_npc.h"
# include "group_profile.h"
//#include "family_behavior.h"
# include "family_profile_tribe.h"
# include "continent_inline.h"
using namespace MULTI_LINE_FORMATER ;
using namespace std ;
using namespace NLMISC ;
using namespace NLNET ;
using namespace RYAI_MAP_CRUNCH ;
using namespace AITYPES ;
CVariable < bool > LogScorerScores ( " ai " , " LogScorerScores " , " " , false , 0 , true ) ;
//////////////////////////////////////////////////////////////////////////////
// CFaunaZone //
//////////////////////////////////////////////////////////////////////////////
CFaunaZone : : CFaunaZone ( CCell * owner , CAIAliasDescriptionNode * adn )
: CAIPlaceXYR ( owner , adn )
{
// nldebug("Creating fauna zone '%s', alias %u", getName().c_str(), getAlias());
}
CFaunaZone : : ~ CFaunaZone ( )
{
// nldebug("Deleting fauna zone '%s', alias %u", getName().c_str(), getAlias());
}
CCell * CFaunaZone : : getOwner ( ) const
{
return static_cast < CCell * > ( CAIPlaceXYR : : getOwner ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////////
// CNpcZone //
//////////////////////////////////////////////////////////////////////////////
CNpcZone : : ~ CNpcZone ( )
{
unlinkNpcZone ( ) ;
}
void CNpcZone : : unlinkNpcZone ( )
{
while ( ! _Roads . empty ( ) )
{
CRoad * road = _Roads . back ( ) ;
if ( road - > startZone ( ) . ptr ( ) = = this )
{
road - > setStartZone ( 0 ) ;
}
else if ( road - > endZone ( ) . ptr ( ) = = this )
{
road - > setEndZone ( 0 ) ;
}
else
{
nlassert ( false ) ;
}
_Roads . pop_back ( ) ;
}
}
float CNpcZone : : getFreeAreaScore ( ) const
{
const float area = getArea ( ) ;
return area / ( ( float ) getNbUse ( ) + 0.001f ) ;
}
std : : string CNpcZone : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + NLMISC : : toString ( " :nz%d " , getIndex ( ) ) ;
}
AITYPES : : CPropertySet & CNpcZone : : properties ( )
{
return _Properties ;
}
const AITYPES : : CPropertySet & CNpcZone : : properties ( ) const
{
return _Properties ;
}
std : : vector < NLMISC : : CDbgPtr < CRoad > > & CNpcZone : : roads ( )
{
return _Roads ;
}
uint32 CNpcZone : : getNbUse ( ) const
{
const sint nbUse = getRefCount ( ) - 1 ; // -1 for the container
# ifdef NL_DEBUG
nlassert ( nbUse > = 0 ) ;
# endif
return nbUse ;
}
//////////////////////////////////////////////////////////////////////////////
// CNpcZonePlace //
//////////////////////////////////////////////////////////////////////////////
CNpcZonePlace : : CNpcZonePlace ( CCell * owner , CAIAliasDescriptionNode * adn )
: CAIPlace ( owner , adn )
{
owner - > getOwner ( ) - > getAIInstance ( ) - > addZone ( getAliasFullName ( ) , this ) ;
// nldebug("Creating npc zone '%s', alias %u", getName().c_str(), getAlias());
}
CNpcZonePlace : : ~ CNpcZonePlace ( )
{
getOwner ( ) - > getOwner ( ) - > getAIInstance ( ) - > removeZone ( getAliasFullName ( ) , this ) ;
// nldebug("Deleting npc zone '%s', alias %u", getName().c_str(), getAlias());
}
CCell * CNpcZonePlace : : getOwner ( ) const
{
return static_cast < CCell * > ( CAIPlace : : getOwner ( ) ) ;
}
const CAliasTreeOwner & CNpcZonePlace : : getAliasTreeOwner ( ) const
{
return * this ;
}
uint32 CNpcZonePlace : : getIndex ( ) const
{
return getIndex ( ) ;
}
CPlaceRandomPos & CNpcZonePlace : : getPlaceRandomPos ( )
{
return * this ;
}
const CPlaceRandomPos & CNpcZonePlace : : getPlaceRandomPos ( ) const
{
return * this ;
}
bool CNpcZonePlace : : atPlace ( const CAIVector & pos ) const
{
return ( pos - _pos ) . sqrnorm ( ) < = ( ( double ) _radius * ( double ) _radius ) ;
}
bool CNpcZonePlace : : atPlace ( const CAIVectorMirror & pos ) const
{
return ( pos - _pos ) . sqrnorm ( ) < = ( ( double ) _radius * ( double ) _radius ) ;
}
bool CNpcZonePlace : : atPlace ( CAIEntityPhysical const * entity ) const
{
return atPlace ( entity - > pos ( ) ) ;
}
const CAIPos & CNpcZonePlace : : midPos ( ) const
{
return _pos ;
}
float CNpcZonePlace : : getArea ( ) const
{
const float radius = getRadius ( ) ;
return ( float ) ( radius * radius * NLMISC : : Pi ) ;
}
const RYAI_MAP_CRUNCH : : CWorldPosition & CNpcZonePlace : : worldValidPos ( ) const
{
return _worldValidPos ;
}
float CNpcZonePlace : : getRadius ( ) const
{
return _radius ;
}
void CNpcZonePlace : : display ( CStringWriter & stringWriter ) const
{
// :TODO: Implement that method
nlassert ( false & & " not yet implemented! " ) ;
}
AITYPES : : TVerticalPos CNpcZonePlace : : getVerticalPos ( ) const
{
return CPlaceRandomPos : : getVerticalPos ( ) ;
}
void CNpcZonePlace : : getRandomPos ( RYAI_MAP_CRUNCH : : CWorldPosition & pos ) const
{
CPlaceRandomPos : : getRandomPos ( pos ) ;
}
void CNpcZonePlace : : setPosAndRadius ( AITYPES : : TVerticalPos verticalPos , const CAIPos & pos , uint32 radius )
{
_VerticalPos = verticalPos ;
_pos = pos ;
_radius = float ( radius ) / 1000.0f ;
# ifdef NL_DEBUG
nlassert ( _radius > 0 ) ;
nlassert ( pos . x ( ) ! = 0 | | pos . y ( ) ! = 0 ) ;
# endif
if ( pos . x ( ) = = 0
& & pos . y ( ) = = 0 )
{
nlwarning ( " Null place Position for %s " , getAliasFullName ( ) . c_str ( ) ) ;
}
if ( ! CWorldContainer : : calcNearestWPosFromPosAnRadius ( _VerticalPos , _worldValidPos , _pos , _radius , 1000 , CWorldContainer : : CPosValidatorDefault ( ) ) )
{
if ( LogAcceptablePos )
nlwarning ( " Unvalid place (no collision free position found) at %d %d " , _pos . x ( ) . asInt ( ) , _pos . y ( ) . asInt ( ) ) ;
}
buildRandomPos ( _worldValidPos , _radius ) ;
}
bool CNpcZonePlace : : calcRandomPos ( CAIPos & pos ) const
{
double dx , dy ;
const double r = ( double ) _radius ;
const double rSquare = r * r ;
// :TODO: Replace that while with a theta/r rand and a space conversion
do
{
dx = CAIS : : frandPlusMinus ( r ) ;
dy = CAIS : : frandPlusMinus ( r ) ;
}
while ( dx * dx + dy * dy > rSquare ) ;
pos . setX ( _pos . x ( ) + dx ) ;
pos . setY ( _pos . y ( ) + dy ) ;
pos . setH ( _pos . h ( ) ) ;
pos . setTheta ( pos . angleTo ( _pos ) + CAngle ( NLMISC : : Pi / 2 ) ) ;
return true ;
}
//////////////////////////////////////////////////////////////////////////////
// CNpcZonePlaceNoPrim //
//////////////////////////////////////////////////////////////////////////////
CNpcZonePlaceNoPrim : : CNpcZonePlaceNoPrim ( )
{
}
CNpcZonePlaceNoPrim : : ~ CNpcZonePlaceNoPrim ( )
{
}
bool CNpcZonePlaceNoPrim : : atPlace ( const CAIVector & pos ) const
{
return ( pos - _Pos ) . sqrnorm ( ) < = ( ( double ) _Radius * ( double ) _Radius ) ;
}
bool CNpcZonePlaceNoPrim : : atPlace ( const CAIVectorMirror & pos ) const
{
return ( pos - _Pos ) . sqrnorm ( ) < = ( ( double ) _Radius * ( double ) _Radius ) ;
}
bool CNpcZonePlaceNoPrim : : atPlace ( CAIEntityPhysical const * entity ) const
{
return atPlace ( entity - > pos ( ) ) ;
}
const CAIPos & CNpcZonePlaceNoPrim : : midPos ( ) const
{
return _Pos ;
}
float CNpcZonePlaceNoPrim : : getArea ( ) const
{
return ( float ) ( _Radius * _Radius * NLMISC : : Pi ) ;
}
const RYAI_MAP_CRUNCH : : CWorldPosition & CNpcZonePlaceNoPrim : : worldValidPos ( ) const
{
return _WorldValidPos ;
}
float CNpcZonePlaceNoPrim : : getRadius ( ) const
{
return _Radius ;
}
void CNpcZonePlaceNoPrim : : display ( CStringWriter & stringWriter ) const
{
// :TODO: Implement that method
nlassert ( false & & " not yet implemented! " ) ;
}
AITYPES : : TVerticalPos CNpcZonePlaceNoPrim : : getVerticalPos ( ) const
{
return AITYPES : : vp_auto ;
}
void CNpcZonePlaceNoPrim : : getRandomPos ( RYAI_MAP_CRUNCH : : CWorldPosition & pos ) const
{
uint maxTries = RandomPosMaxRetry ;
CAIPos dummyPos ;
bool foundRandomPos = false ;
while ( ! foundRandomPos )
{
if ( calcRandomPos ( dummyPos ) )
foundRandomPos = CWorldContainer : : getWorldMap ( ) . setWorldPosition ( _VerticalPos , pos , dummyPos ) ;
- - maxTries ;
if ( maxTries < = 0 )
break ;
}
if ( ! foundRandomPos )
{
if ( ! CWorldContainer : : calcNearestWPosFromPosAnRadius ( _VerticalPos , pos , _WorldValidPos , _Radius , 1000 , CWorldContainer : : CPosValidatorDefault ( ) ) )
{
if ( LogAcceptablePos )
nlwarning ( " Unvalid place (no collision free position found) at %d %d " , _WorldValidPos . toAIVector ( ) . x ( ) . asInt ( ) , _WorldValidPos . toAIVector ( ) . y ( ) . asInt ( ) ) ;
}
}
}
void CNpcZonePlaceNoPrim : : setPosAndRadius ( AITYPES : : TVerticalPos verticalPos , const CAIPos & pos , uint32 radius )
{
# ifdef NL_DEBUG
nlassert ( radius > 0 ) ;
nlassert ( pos . x ( ) ! = 0 | | pos . y ( ) ! = 0 ) ;
# endif
_VerticalPos = verticalPos ;
_Pos = pos ;
_Radius = float ( radius ) / 1000.0f ;
if ( ! CWorldContainer : : calcNearestWPosFromPosAnRadius ( _VerticalPos , _WorldValidPos , _Pos , _Radius , 1000 , CWorldContainer : : CPosValidatorDefault ( ) ) )
{
if ( LogAcceptablePos )
nlwarning ( " Unvalid place (no collision free position found) at %d %d " , _Pos . x ( ) . asInt ( ) , _Pos . y ( ) . asInt ( ) ) ;
}
}
bool CNpcZonePlaceNoPrim : : calcRandomPos ( CAIPos & pos ) const
{
double dx , dy ;
const double r = ( double ) _Radius ;
const double rSquare = r * r ;
// :TODO: Replace that while with a theta/r rand and a space conversion
do
{
dx = CAIS : : frandPlusMinus ( r ) ;
dy = CAIS : : frandPlusMinus ( r ) ;
}
while ( dx * dx + dy * dy > rSquare ) ;
pos . setX ( _Pos . x ( ) + dx ) ;
pos . setY ( _Pos . y ( ) + dy ) ;
pos . setH ( _Pos . h ( ) ) ;
pos . setTheta ( pos . angleTo ( _Pos ) + CAngle ( NLMISC : : Pi / 2 ) ) ;
return true ;
}
//////////////////////////////////////////////////////////////////////////////
// CNpcZoneShape //
//////////////////////////////////////////////////////////////////////////////
CNpcZoneShape : : CNpcZoneShape ( CCell * owner , CAIAliasDescriptionNode * adn )
: CAIPlace ( owner , adn )
{
owner - > getOwner ( ) - > getAIInstance ( ) - > addZone ( getAliasFullName ( ) , this ) ;
// nldebug("Creating npc zone '%s', alias %u", getName().c_str(), getAlias());
}
CNpcZoneShape : : ~ CNpcZoneShape ( )
{
getOwner ( ) - > getOwner ( ) - > getAIInstance ( ) - > removeZone ( getAliasFullName ( ) , this ) ;
// nldebug("Deleting npc zone '%s', alias %u", getName().c_str(), getAlias());
}
CCell * CNpcZoneShape : : getOwner ( ) const
{
return static_cast < CCell * > ( CAIPlace : : getOwner ( ) ) ;
}
const CAliasTreeOwner & CNpcZoneShape : : getAliasTreeOwner ( ) const
{
return * this ;
}
uint32 CNpcZoneShape : : getIndex ( ) const
{
return getIndex ( ) ;
}
CPlaceRandomPos & CNpcZoneShape : : getPlaceRandomPos ( )
{
return this - > _shape ;
}
const CPlaceRandomPos & CNpcZoneShape : : getPlaceRandomPos ( ) const
{
return this - > _shape ;
}
bool CNpcZoneShape : : atPlace ( const CAIVector & pos ) const
{
return _shape . contains ( pos ) ;
}
bool CNpcZoneShape : : atPlace ( const CAIVectorMirror & pos ) const
{
return _shape . contains ( pos ) ;
}
bool CNpcZoneShape : : atPlace ( CAIEntityPhysical const * entity ) const
{
return atPlace ( entity - > pos ( ) ) ;
}
const CAIPos & CNpcZoneShape : : midPos ( ) const
{
return _midPos ;
}
float CNpcZoneShape : : getArea ( ) const
{
const float area = 20.0f ;
nlwarning ( " CNpcZoneShape area asked although it's a fake value. " ) ;
return area ;
}
const RYAI_MAP_CRUNCH : : CWorldPosition & CNpcZoneShape : : worldValidPos ( ) const
{
return _worldValidPos ;
}
float CNpcZoneShape : : getRadius ( ) const
{
const float radius = 1.0f ;
return radius ;
}
void CNpcZoneShape : : display ( CStringWriter & stringWriter ) const
{
// :TODO: Implement that method
nlassert ( false & & " not yet implemented! " ) ;
}
AITYPES : : TVerticalPos CNpcZoneShape : : getVerticalPos ( ) const
{
return _shape . getVerticalPos ( ) ;
}
void CNpcZoneShape : : getRandomPos ( RYAI_MAP_CRUNCH : : CWorldPosition & pos ) const
{
_shape . getRandomPos ( pos ) ;
}
void CNpcZoneShape : : setPatat ( AITYPES : : TVerticalPos verticalPos , const std : : vector < CAIVector > & points )
{
if ( ! _shape . setPatat ( verticalPos , points ) )
{
nlwarning ( " CNpcZoneShape::setPatat: error while placing the points of '%s' " ,
getAliasFullName ( ) . c_str ( ) ) ;
}
buildMidPos ( ) ;
}
void CNpcZoneShape : : buildMidPos ( )
{
//nlassert(false && "build appropriate _midPos");
int count = 0 ;
bool succeeded = _shape . calcRandomPos ( _midPos ) ;
while ( ! succeeded & & count < 1000 )
{
succeeded = _shape . calcRandomPos ( _midPos ) ;
+ + count ;
}
}
//////////////////////////////////////////////////////////////////////////////
// CCell //
//////////////////////////////////////////////////////////////////////////////
std : : string CCell : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + NLMISC : : toString ( " :ce%d " , getChildIndex ( ) ) ;
}
void CCell : : connectRoads ( )
{
CContinent & continent = * getOwner ( ) - > getOwner ( ) - > getOwner ( ) ;
vector < CCell * > neighBourgCellList ;
getNeighBourgCellList ( neighBourgCellList ) ;
for ( uint i = 0 ; i < _Roads . size ( ) ; + + i )
{
CRoad * road = roads ( ) [ i ] ;
if ( ! road )
continue ;
road - > calcLength ( ) ;
// clear existing link;
road - > unlinkRoad ( ) ;
if ( road - > coords ( ) . size ( ) > 1 )
{
// ok, there are 2 points, try to found the zone they belong to
// starting zone try first in the same CCell, after in the neighbourg, and last in the whole continent.
CNpcZone * nz = findNpcZone ( road - > getLogicStart ( ) ) ;
if ( ! nz )
{
FOREACH ( itCell , vector < CCell * > , neighBourgCellList )
{
nz = ( * itCell ) - > findNpcZone ( road - > getLogicStart ( ) ) ;
if ( nz )
break ;
}
}
if ( ! nz )
nz = continent . findNpcZone ( road - > getLogicStart ( ) ) ;
if ( nz )
{
// ok, we found the first zone
road - > setStartZone ( nz ) ;
nz - > roads ( ) . push_back ( road ) ;
}
else
{
//#if !FINAL_VERSION
nlwarning ( " Road '%s'%s end don't reach a zone at %s " ,
road - > getAliasFullName ( ) . c_str ( ) ,
road - > getAliasString ( ) . c_str ( ) ,
road - > getLogicStart ( ) . toString ( ) . c_str ( ) ) ;
//#endif
}
// ending zone
nz = findNpcZone ( road - > getLogicEnd ( ) ) ;
if ( ! nz )
{
FOREACH ( itCell , vector < CCell * > , neighBourgCellList )
{
nz = ( * itCell ) - > findNpcZone ( road - > getLogicEnd ( ) ) ;
if ( nz )
break ;
}
}
if ( ! nz )
nz = continent . findNpcZone ( road - > getLogicEnd ( ) ) ;
if ( nz )
{
// ok, we found the first zone
road - > setEndZone ( nz ) ;
nz - > roads ( ) . push_back ( road ) ;
}
else
{
//#ifndef FINAL_VERSION
nlwarning ( " Road '%s'%s: end don't reach a zone at %s " ,
road - > getAliasFullName ( ) . c_str ( ) ,
road - > getAliasString ( ) . c_str ( ) ,
road - > getLogicEnd ( ) . toString ( ) . c_str ( ) ) ;
//#endif
}
}
else
{
//#ifndef FINAL_VERSION
if ( road - > coords ( ) . size ( ) = = 1 )
{
nlwarning ( " Road '%s'%s: only one point at %s " ,
road - > getAliasFullName ( ) . c_str ( ) ,
road - > getAliasString ( ) . c_str ( ) ,
road - > getLogicStart ( ) . toString ( ) . c_str ( ) ) ;
}
//#endif
}
}
}
//////////////////////////////////////////////////////////////////////////////
// CContinent //
//////////////////////////////////////////////////////////////////////////////
CContinent : : ~ CContinent ( )
{
// first, despawn all groups in familyBehaviors managers
FOREACH ( itRegion , CAliasCont < CRegion > , _Regions )
{
FOREACH ( itCZ , CAliasCont < CCellZone > , itRegion - > cellZones ( ) )
{
FOREACH ( itFB , CCont < CFamilyBehavior > , itCZ - > familyBehaviors ( ) )
{
// unspawn in the npc manager
CManager * mgrNpc = itFB - > mgrNpc ( ) ;
mgrNpc - > groups ( ) . setChildSize ( 0 ) ;
CManager * mgrFauna = itFB - > mgrFauna ( ) ;
mgrFauna - > groups ( ) . setChildSize ( 0 ) ;
}
}
}
}
IAliasCont * CContinent : : getAliasCont ( TAIType type )
{
switch ( type )
{
case AITypeDynamicRegion :
return & _Regions ;
case AITypeOutpost :
return & _Outposts ;
default :
return NULL ;
}
}
std : : string CContinent : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + NLMISC : : toString ( " :c%u " , getChildIndex ( ) ) ;
}
std : : string CContinent : : getOneLineInfoString ( ) const
{
return std : : string ( " Continent ' " ) + getName ( ) + " ' " ;
}
std : : vector < std : : string > CContinent : : getMultiLineInfoString ( ) const
{
std : : vector < std : : string > container ;
pushTitle ( container , " CContinent " ) ;
pushEntry ( container , " id= " + getIndexString ( ) ) ;
container . back ( ) + = " name= " + getName ( ) ;
pushEntry ( container , " fullname= " + getFullName ( ) ) ;
pushFooter ( container ) ;
return container ;
}
CNpcZone * CContinent : : findNpcZone ( CAIVector const & posInside )
{
for ( CCont < CRegion > : : iterator itRegion = _Regions . begin ( ) , itEndRegion = _Regions . end ( ) ; itRegion ! = itEndRegion ; + + itRegion )
{
for ( CCont < CCellZone > : : iterator itCellZone = itRegion - > cellZones ( ) . begin ( ) , itEndCellZone = itRegion - > cellZones ( ) . end ( ) ; itCellZone ! = itEndCellZone ; + + itCellZone )
{
for ( CCont < CCell > : : iterator itCell = itCellZone - > cells ( ) . begin ( ) , itEndCell = itCellZone - > cells ( ) . end ( ) ; itCell ! = itEndCell ; + + itCell )
{
CNpcZone * npcZone = itCell - > findNpcZone ( posInside ) ;
if ( npcZone )
return npcZone ;
}
}
}
// no zone match the position !
return NULL ;
}
bool CContinent : : markTagForDelete ( NLMISC : : TStringId fileId )
{
CAliasTreeRoot : : CMarkTagForDelete const deleteMarker ( fileId ) ;
for_each ( _Regions . begin ( ) , _Regions . end ( ) , deleteMarker ) ;
for_each ( _Outposts . begin ( ) , _Outposts . end ( ) , deleteMarker ) ;
return true ;
}
bool CContinent : : deleteTaggedAlias ( NLMISC : : TStringId fileId )
{
for_each ( _Regions . begin ( ) , _Regions . end ( ) , CAliasTreeRoot : : CDeleteTagged < CRegion > ( _Regions ) ) ;
for_each ( _Outposts . begin ( ) , _Outposts . end ( ) , CAliasTreeRoot : : CDeleteTagged < COutpost > ( _Outposts ) ) ;
return true ;
}
void CContinent : : updateLazyProcess ( )
{
if ( _LazyProcess . size ( ) < = 0 )
return ;
FOREACH ( lazy , TLazyProcessList , _LazyProcess )
( * lazy ) - > update ( ) ;
_LazyProcess . clear ( ) ;
}
void CContinent : : pushLazyProcess ( CSmartPtr < CLazyProcess > lazyProcess )
{
FOREACH ( lazy , TLazyProcessList , _LazyProcess )
if ( ( * lazy ) - > absorb ( * lazyProcess ) )
return ;
_LazyProcess . push_back ( lazyProcess ) ;
}
void CRebuildContinentAndOutPost : : update ( ) const
{
nlinfo ( " Build Continent %s dependencies .. " , _Continent - > getFullName ( ) . c_str ( ) ) ;
// rebuild the bounding box
_Continent - > rebuildBoundingBox ( ) ;
// rebuild the connectivity graph
FOREACH ( region , CAliasCont < CRegion > , _Continent - > regions ( ) )
region - > rebuildConnectivity ( ) ;
/*
// relocate the outpost into the correct cellZone
FOREACH ( outpost , CAliasCont < COutpost > , _Continent - > outposts ( ) )
{
CCellZone * const czone = _Continent - > getOwner ( ) - > locateCellZoneForPos ( outpost - > getPosition ( ) ) ;
outpost - > setCellZone ( czone ) ;
// relink outpost and tribe
_Continent - > relinkOutpost ( ) ;
}
*/
}
void CContinent : : update ( )
{
updateLazyProcess ( ) ;
{
H_AUTO ( RegionsUpdate )
// update all the regions
FOREACH ( region , CAliasCont < CRegion > , _Regions )
( * region ) - > update ( ) ;
}
{
H_AUTO ( OutpostsUpdate )
// update all the outpost
FOREACH ( outpost , CAliasCont < COutpost > , _Outposts )
( * outpost ) - > update ( ) ;
}
}
void CContinent : : rebuildBoundingBox ( )
{
// build the AABB to speedup the task
_BoundingBox . init ( ) ;
for ( uint i = 0 ; i < _Regions . size ( ) ; + + i )
{
CRegion * region = _Regions [ i ] ;
if ( ! region )
continue ;
region - > rebuildBoundingBox ( ) ;
_BoundingBox . includeAabb ( region - > _BoundingBox ) ;
}
}
void CContinent : : serviceEvent ( const CServiceEvent & info )
{
CCont < CRegion > : : iterator itRegion = _Regions . begin ( ) , itRegionEnd = _Regions . end ( ) ;
while ( itRegion ! = itRegionEnd )
{
itRegion - > serviceEvent ( info ) ;
+ + itRegion ;
}
CCont < COutpost > : : iterator itOutpost = _Outposts . begin ( ) , itOutpostEnd = _Outposts . end ( ) ;
while ( itOutpost ! = itOutpostEnd )
{
itOutpost - > serviceEvent ( info ) ;
+ + itOutpost ;
}
}
bool CContinent : : spawn ( )
{
// Spawn regions
for ( size_t i = 0 ; i < _Regions . size ( ) ; + + i )
{
2010-05-18 14:53:47 +00:00
CRegion * region = _Regions [ ( uint32 ) i ] ;
2010-05-06 00:08:41 +00:00
if ( ! region )
continue ;
region - > spawn ( ) ;
}
// Spawn outposts
for ( size_t i = 0 ; i < _Outposts . size ( ) ; + + i )
{
2010-05-18 14:53:47 +00:00
COutpost * outpost = _Outposts [ ( uint32 ) i ] ;
2010-05-06 00:08:41 +00:00
if ( ! outpost )
continue ;
outpost - > spawn ( ) ;
}
// We should check individual errors, but fake success here :)
return true ;
}
bool CContinent : : despawn ( )
{
// Despawn regions
for ( size_t i = 0 ; i < _Regions . size ( ) ; + + i )
{
2010-05-18 14:53:47 +00:00
CRegion * region = _Regions [ ( uint32 ) i ] ;
2010-05-06 00:08:41 +00:00
if ( ! region )
continue ;
region - > despawn ( ) ;
}
// Despawn outposts
for ( size_t i = 0 ; i < _Outposts . size ( ) ; + + i )
{
2010-05-18 14:53:47 +00:00
COutpost * outpost = _Outposts [ ( uint32 ) i ] ;
2010-05-06 00:08:41 +00:00
if ( ! outpost )
continue ;
outpost - > despawn ( ) ;
}
// We should check individual errors, but fake success here :)
return true ;
}
//////////////////////////////////////////////////////////////////////////////
// CRegion //
//////////////////////////////////////////////////////////////////////////////
CRegion : : CRegion ( CContinent * owner , uint32 alias , std : : string const & name , std : : string const & filename )
: CAliasChild < CContinent > ( owner , alias , name )
, CAliasTreeRoot ( filename )
{
}
CRegion : : ~ CRegion ( )
{
_CellZones . clear ( ) ;
_GroupFamilies . clear ( ) ;
nldebug ( " Deleting region '%s'%s " , getName ( ) . c_str ( ) , getAliasString ( ) . c_str ( ) ) ;
}
IAliasCont * CRegion : : getAliasCont ( TAIType type )
{
switch ( type )
{
case AITypeCellZone :
return & _CellZones ;
case AITypeGroupFamilyProfileFauna :
case AITypeGroupFamilyProfileTribe :
return & _GroupFamilies ;
case AITypeGroupFamilyProfileNpc :
return & _GroupFamilies ;
default :
return NULL ;
}
}
CAliasTreeOwner * CRegion : : createChild ( IAliasCont * cont , CAIAliasDescriptionNode * aliasTree )
{
if ( ! cont )
return NULL ;
CAliasTreeOwner * child = NULL ;
switch ( aliasTree - > getType ( ) )
{
// create the child and adds it to the corresponding position.
case AITypeCellZone :
child = new CCellZone ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
case AITypeGroupFamilyProfileFauna :
case AITypeGroupFamilyProfileTribe :
child = new CGroupFamily ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
case AITypeGroupFamilyProfileNpc :
child = new CGroupFamily ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
default :
break ;
}
if ( child )
cont - > addAliasChild ( child ) ;
return child ;
}
std : : string CRegion : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + toString ( " :r%u " , getChildIndex ( ) ) ;
}
std : : string CRegion : : getOneLineInfoString ( ) const
{
return std : : string ( " Region ' " ) + getName ( ) + " ' " ;
}
std : : vector < std : : string > CRegion : : getMultiLineInfoString ( ) const
{
std : : vector < std : : string > container ;
pushTitle ( container , " CRegion " ) ;
pushEntry ( container , " id= " + getIndexString ( ) ) ;
container . back ( ) + = " alias= " + getAliasString ( ) ;
container . back ( ) + = " name= " + getName ( ) ;
pushEntry ( container , " fullname= " + getFullName ( ) ) ;
pushFooter ( container ) ;
return container ;
}
std : : string CRegion : : getFullName ( ) const
{
return std : : string ( getOwner ( ) - > getFullName ( ) + " : " + getName ( ) ) ;
}
void CRegion : : rebuildBoundingBox ( )
{
// build the AABB to speedup the task
_BoundingBox . init ( ) ;
for ( uint i = 0 ; i < _CellZones . size ( ) ; + + i )
{
CCellZone * czone = _CellZones [ i ] ;
if ( ! czone )
continue ;
// CAIVector vmaxZone(INT_MIN/CAICoord::UNITS_PER_METER, INT_MIN/CAICoord::UNITS_PER_METER);
// CAIVector vminZone(INT_MAX/CAICoord::UNITS_PER_METER, INT_MAX/CAICoord::UNITS_PER_METER);
czone - > _BoundingBox . init ( ) ;
for ( uint j = 0 ; j < czone - > cells ( ) . size ( ) ; + + j )
{
CCell * cell = czone - > cells ( ) [ j ] ;
if ( ! cell )
continue ;
cell - > _BoundingBox = CAabb ( cell - > _Coords ) ;
czone - > _BoundingBox . includeAabb ( cell - > _BoundingBox ) ;
}
_BoundingBox . includeAabb ( czone - > _BoundingBox ) ;
}
}
void CRegion : : rebuildConnectivity ( )
{
nlinfo ( " Build Region '%s' dependencies .. " , getFullName ( ) . c_str ( ) ) ;
// prestep : clear the road and cell connectivity
FOREACH ( czone , CAliasCont < CCellZone > , _CellZones )
{
czone - > rebuildEnergyLevels ( ) ;
FOREACH ( itCell , CCont < CCell > , czone - > cells ( ) )
{
itCell - > _NeighbourCells . clear ( ) ;
for ( TAliasZonePlaceList : : iterator itZone = itCell - > npcZonePlaces ( ) . begin ( ) , itEndZone = itCell - > npcZonePlaces ( ) . end ( ) ; itZone ! = itEndZone ; + + itZone )
itZone - > roads ( ) . clear ( ) ;
for ( TAliasZoneShapeList : : iterator itZone = itCell - > npcZoneShapes ( ) . begin ( ) , itEndZone = itCell - > npcZoneShapes ( ) . end ( ) ; itZone ! = itEndZone ; + + itZone )
itZone - > roads ( ) . clear ( ) ;
}
}
// First pass : build the connectivity between cells
const double SCALE_DIAG = 1 / 10.0 ;
for ( uint i = 0 ; i < _CellZones . size ( ) ; + + i )
{
CCellZone * czone = _CellZones [ i ] ;
if ( ! czone )
continue ;
for ( uint j = 0 ; j < czone - > cells ( ) . size ( ) ; + + j )
{
CCell * cell1 = czone - > cells ( ) [ j ] ;
if ( ! cell1 )
continue ;
// maximum dist for aproximation of contact
double epsilon1 = ( cell1 - > _BoundingBox . vmax ( ) - cell1 - > _BoundingBox . vmin ( ) ) . norm ( ) * SCALE_DIAG ;
// for (uint k=i; k<_CellZones.size(); ++k)
{
CCellZone * czone2 = czone ; //_CellZones[k];
if ( ! czone2 )
continue ;
for ( uint l = 0 ; l < czone2 - > cells ( ) . size ( ) ; + + l )
{
CCell * cell2 = czone - > cells ( ) [ l ] ;
if ( ! cell2
| | cell2 = = cell1
| | cell1 - > _NeighbourCells . find ( cell2 ) ! = cell1 - > _NeighbourCells . end ( ) )
continue ;
if ( cell2 - > _NeighbourCells . find ( cell1 ) ! = cell2 - > _NeighbourCells . end ( ) )
{
nlassert ( false ) ;
continue ;
}
double epsilon2 = ( cell2 - > _BoundingBox . vmax ( ) - cell2 - > _BoundingBox . vmin ( ) ) . norm ( ) * SCALE_DIAG ;
double epsilon = max ( epsilon1 , epsilon2 ) ;
// check distance between AABB to reduce vertex checking
// check on X
if ( cell1 - > _BoundingBox . vmin ( ) . x ( ) < cell2 - > _BoundingBox . vmin ( ) . x ( ) )
{
// cell 1 on left of cell 2
if ( ( cell2 - > _BoundingBox . vmin ( ) . x ( ) - cell1 - > _BoundingBox . vmax ( ) . x ( ) ) > epsilon )
continue ;
}
else
{
// cell 1 on right of cell 2
if ( ( cell1 - > _BoundingBox . vmin ( ) . x ( ) - cell2 - > _BoundingBox . vmax ( ) . x ( ) ) > epsilon )
continue ;
}
// check on Y
if ( cell1 - > _BoundingBox . vmin ( ) . y ( ) < cell2 - > _BoundingBox . vmin ( ) . y ( ) )
{
// cell 1 on left of cell 2
if ( ( cell2 - > _BoundingBox . vmin ( ) . y ( ) - cell1 - > _BoundingBox . vmax ( ) . y ( ) ) > epsilon )
continue ;
}
else
{
// cell 1 on right of cell 2
if ( ( cell1 - > _BoundingBox . vmin ( ) . y ( ) - cell2 - > _BoundingBox . vmax ( ) . y ( ) ) > epsilon )
continue ;
}
// ok, if we are there, the bouding box overlaps or are close enough
// run through the points of each cell
{
// square the espilon to check distance faster
epsilon = std : : min ( epsilon , 4.0 ) ;
epsilon = epsilon * epsilon ;
uint32 nbCnx = 0 ;
for ( uint i = 0 ; i < cell1 - > _Coords . size ( ) ; + + i )
{
for ( uint j = 0 ; j < cell2 - > _Coords . size ( ) ; + + j )
{
if ( ( cell1 - > _Coords [ i ] - cell2 - > _Coords [ j ] ) . sqrnorm ( ) < epsilon )
nbCnx + + ;
}
}
if ( nbCnx > 1 )
{
// ok, the two cells are connected.
bool ok = cell1 - > _NeighbourCells . insert ( cell2 ) . second ;
ok = cell2 - > _NeighbourCells . insert ( cell1 ) . second ;
// nldebug("Connecting cell '%s' with '%s'", cell1->getName().c_str(), cell2->getName().c_str());
}
}
}
}
}
}
// second pass, link road with cells
FOREACH ( czone , CAliasCont < CCellZone > , _CellZones )
{
FOREACH ( itCell , CCont < CCell > , czone - > cells ( ) )
{
itCell - > connectRoads ( ) ;
}
}
}
void CRegion : : update ( )
{
for ( uint j = 0 ; j < _CellZones . size ( ) ; + + j )
{
CCellZone * czone = _CellZones [ j ] ;
if ( ! czone )
continue ;
czone - > update ( ) ;
}
}
void CRegion : : serviceEvent ( const CServiceEvent & info )
{
CCont < CCellZone > : : iterator first ( _CellZones . begin ( ) ) , last ( _CellZones . end ( ) ) ;
for ( ; first ! = last ; + + first )
{
( * first ) - > serviceEvent ( info ) ;
}
}
bool CRegion : : spawn ( )
{
// Spawn cellzones
for ( size_t j = 0 ; j < _CellZones . size ( ) ; + + j )
{
2010-05-18 14:53:47 +00:00
CCellZone * cellZone = _CellZones [ ( uint32 ) j ] ;
2010-05-06 00:08:41 +00:00
if ( ! cellZone )
continue ;
cellZone - > spawn ( ) ;
}
// We should check individual errors, but fake success here :)
return true ;
}
bool CRegion : : despawn ( )
{
// Despawn cellzones
for ( size_t j = 0 ; j < _CellZones . size ( ) ; + + j )
{
2010-05-18 14:53:47 +00:00
CCellZone * cellZone = _CellZones [ ( uint32 ) j ] ;
2010-05-06 00:08:41 +00:00
if ( ! cellZone )
continue ;
cellZone - > despawn ( ) ;
}
// We should check individual errors, but fake success here :)
return true ;
}
//////////////////////////////////////////////////////////////////////////////
// CGroupFamily //
//////////////////////////////////////////////////////////////////////////////
IAliasCont * CGroupFamily : : getAliasCont ( TAIType type )
{
switch ( type )
{
case AITypeGroupTemplate :
case AITypeGroupTemplateMultiLevel :
case AITypeGroupTemplateFauna :
return & _GroupDescs ;
break ;
case AITypeGroupTemplateNpc :
return & _GroupDescs ;
default :
return NULL ;
}
}
CAliasTreeOwner * CGroupFamily : : createChild ( IAliasCont * cont , CAIAliasDescriptionNode * aliasTree )
{
if ( ! cont )
return NULL ;
CAliasTreeOwner * child = NULL ;
switch ( aliasTree - > getType ( ) )
{
case AITypeGroupTemplate :
case AITypeGroupTemplateMultiLevel :
case AITypeGroupTemplateFauna :
case AITypeGroupTemplateNpc :
child = new CGroupDesc < CGroupFamily > ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
default :
break ;
}
if ( child )
cont - > addAliasChild ( child ) ;
return child ;
}
const CGroupDesc < CGroupFamily > * CGroupFamily : : getProportionalGroupDesc ( const CFamilyBehavior * const familyBehavior , const CPropertySet & needActFlag , const CPropertySet & maskActFlag )
{
H_AUTO ( getProportionalGroupDesc )
// first, build a list of group that match
// the family, energy level and spawn type
// TODO
// const TPopulationFamily &family =familyBehavior->getFamily();
const uint32 level = familyBehavior - > getLevelIndex ( ) ;
vector < const CGroupDesc < CGroupFamily > * > groups ;
const bool & isDay = CTimeInterface : : isDay ( ) ;
uint32 totalWeight = 0 ;
uint32 totalSpawnGroup = 0 ;
for ( uint i = 0 ; i < _GroupDescs . size ( ) ; + + i )
{
const CGroupDesc < CGroupFamily > * const gd = _GroupDescs [ i ] ;
if ( ! gd )
continue ;
const uint32 weight = gd - > getWeightForEnergy ( level ) ;
if ( weight < = 0 )
continue ;
if ( ! gd - > isValidForSeason ( CTimeInterface : : season ( ) ) )
continue ;
if ( ! gd - > isValidForDayOrNight ( isDay ) )
continue ;
if ( gd - > properties ( ) . containsPartOfStrict ( maskActFlag ) )
continue ;
if ( ! gd - > properties ( ) . containsAllOf ( needActFlag ) )
continue ;
totalWeight + = weight ;
totalSpawnGroup + = gd - > getNbUse ( ) ;
groups . push_back ( gd ) ;
}
if ( groups . empty ( ) )
{
if ( ! LogGroupCreationFailure )
return NULL ;
return NULL ;
}
float maxScore = 0 ;
const CGroupDesc < CGroupFamily > * choosenGroup = NULL ;
for ( std : : vector < const CGroupDesc < CGroupFamily > * > : : iterator it = groups . begin ( ) , itEnd = groups . end ( ) ; it ! = itEnd ; + + it )
{
// score to reach theorical rate.
const float score = ( ( * it ) - > getWeightForEnergy ( level ) * totalSpawnGroup )
- ( ( float ) ( * it ) - > getNbUse ( ) * totalWeight ) ;
if ( score < maxScore )
continue ;
choosenGroup = * it ;
maxScore = score ;
}
return choosenGroup ;
}
//////////////////////////////////////////////////////////////////////////////
// CGroupDesc //
//////////////////////////////////////////////////////////////////////////////
template < > size_t const CGroupDesc < CGroupFamily > : : _MultiLevelSheetCount = 20 ;
//////////////////////////////////////////////////////////////////////////////
// CBotDesc //
//////////////////////////////////////////////////////////////////////////////
template < > size_t const CBotDesc < CGroupFamily > : : _MultiLevelSheetCount = 20 ;
//////////////////////////////////////////////////////////////////////////////
// CRoad //
//////////////////////////////////////////////////////////////////////////////
CRoad : : CRoad ( CCell * owner , uint32 alias , const std : : string & name )
: CAliasChild < CCell > ( owner , alias , name ) ,
_StartZone ( ) , _StartExternal ( false ) , _EndZone ( ) , _EndExternal ( false )
{
// nldebug("Creating road '%s', alias %u", getName().c_str(), getAlias());
}
CRoad : : ~ CRoad ( )
{
// nldebug("Deleting road '%s', alias %u", getName().c_str(), getAlias());
// need to unlink the road from the start and end zones
unlinkRoad ( ) ;
}
void CRoad : : unlinkRoad ( )
{
// unlink the road from the start and end zones
if ( ! _StartZone . isNULL ( ) )
{
std : : vector < NLMISC : : CDbgPtr < CRoad > > & roads = _StartZone - > roads ( ) ;
roads . erase ( std : : remove ( roads . begin ( ) , roads . end ( ) , CDbgPtr < CRoad > ( this ) ) , roads . end ( ) ) ;
}
_StartZone = ( CNpcZone * ) NULL ;
if ( ! _EndZone . isNULL ( ) )
{
std : : vector < NLMISC : : CDbgPtr < CRoad > > & roads = _EndZone - > roads ( ) ;
roads . erase ( std : : remove ( roads . begin ( ) , roads . end ( ) , CDbgPtr < CRoad > ( this ) ) , roads . end ( ) ) ;
}
_EndZone = ( CNpcZone * ) NULL ;
}
IAliasCont * CRoad : : getAliasCont ( TAIType type )
{
switch ( type )
{
case AITypeRoadTrigger :
return & _RoadTriggers ;
default :
return NULL ;
}
}
CAliasTreeOwner * CRoad : : createChild ( IAliasCont * cont , CAIAliasDescriptionNode * aliasTree )
{
if ( ! cont )
return NULL ;
CAliasTreeOwner * child = NULL ;
switch ( aliasTree - > getType ( ) )
{
// create the child and adds it to the corresponding position.
case AITypeRoadTrigger :
child = new CRoadTrigger ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
}
if ( child )
cont - > addAliasChild ( child ) ;
return child ;
}
std : : string CRoad : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + NLMISC : : toString ( " :ro%u " , getChildIndex ( ) ) ;
}
void CRoad : : setPathPoints ( TVerticalPos verticalPos , const std : : vector < CAIVector > & points )
{
_VerticalPos = verticalPos ;
for ( uint i = 0 ; i < points . size ( ) ; + + i )
{
RYAI_MAP_CRUNCH : : CWorldPosition newpos ;
CWorldContainer : : calcNearestWPosFromPosAnRadius ( _VerticalPos , newpos , points [ i ] , 0 , 1 , CWorldContainer : : CPosValidatorDefault ( ) ) ;
if ( ! newpos . isValid ( ) )
{
CWorldContainer : : calcNearestWPosFromPosAnRadius ( _VerticalPos , newpos , points [ i ] , 6 , 100 , CWorldContainer : : CPosValidatorDefault ( ) ) ;
if ( newpos . isValid ( ) )
{
if ( LogAcceptablePos )
nlinfo ( " DynRoad '%s'%s: Path pos Error at position %s for size %d, an acceptable position could be %s " ,
getAliasFullName ( ) . c_str ( ) ,
getAliasString ( ) . c_str ( ) ,
points [ i ] . toString ( ) . c_str ( ) ,
0 ,
newpos . toString ( ) . c_str ( ) ) ;
}
else
nlwarning ( " Dynroad '%s'%s: Path pos Error at position %s for size %d, no acceptable position found around " ,
getAliasFullName ( ) . c_str ( ) ,
getAliasString ( ) . c_str ( ) ,
points [ i ] . toString ( ) . c_str ( ) ,
0 ) ;
}
_Coords . push_back ( newpos ) ;
}
if ( points . size ( ) > 0 )
_Start = points . front ( ) ;
if ( points . size ( ) > 1 )
_End = points . back ( ) ;
}
void CRoad : : setStartZone ( const CNpcZone * const npcZone )
{
_StartZone = ( CNpcZone * ) npcZone ;
if ( ! npcZone )
{
_StartExternal = false ;
}
else
{
_StartExternal = npcZone - > getOwner ( ) - > getOwner ( ) - > getOwner ( ) ! = getOwner ( ) - > getOwner ( ) - > getOwner ( ) ;
}
}
void CRoad : : setEndZone ( const CNpcZone * const npcZone )
{
_EndZone = npcZone ;
if ( ! npcZone )
{
_EndExternal = false ;
}
else
{
_EndExternal = npcZone - > getOwner ( ) - > getOwner ( ) - > getOwner ( ) ! = getOwner ( ) - > getOwner ( ) - > getOwner ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////////
// CCellZone //
//////////////////////////////////////////////////////////////////////////////
struct CCellChoice
{
struct CZoneScore
{
float score ;
const CFaunaZone * zone ;
} ;
CCellChoice ( )
{
for ( uint32 i = 0 ; i < MAX_ZONE_SCORE ; i + + )
{
zones [ i ] . score = 0 ;
zones [ i ] . zone = NULL ;
}
}
float getTotalScore ( ) const
{
float totalScore = 1 ;
for ( uint32 i = 0 ; i < MAX_ZONE_SCORE ; i + + )
totalScore * = zones [ i ] . score ;
return totalScore ;
}
enum TZoneScoreType
{
FOOD_ZONE_SCORE = 0 ,
REST_ZONE_SCORE = 1 ,
MAX_ZONE_SCORE = 2
} ;
CZoneScore zones [ MAX_ZONE_SCORE ] ;
} ;
CCellZone : : CCellZone ( CRegion * owner , uint32 alias , const std : : string & name )
: CAliasChild < CRegion > ( owner , alias , name )
{
nldebug ( " Creating cell zone '%s'%s " ,
getName ( ) . c_str ( ) ,
getAliasString ( ) . c_str ( ) ) ;
}
CCellZone : : ~ CCellZone ( )
{
// clear the families first to despawn all the groups (managers are in the families)
_Families . clear ( ) ;
_Cells . clear ( ) ;
nldebug ( " Deleting cell zone '%s'%s " ,
getName ( ) . c_str ( ) ,
getAliasString ( ) . c_str ( ) ) ;
}
std : : string CCellZone : : getOneLineInfoString ( ) const
{
return std : : string ( " Cell zone ' " ) + getName ( ) + " ' " ;
}
std : : vector < std : : string > CCellZone : : getMultiLineInfoString ( ) const
{
std : : vector < std : : string > container ;
pushTitle ( container , " CCellZone " ) ;
pushEntry ( container , " id= " + getIndexString ( ) ) ;
container . back ( ) + = " name= " + getName ( ) ;
pushEntry ( container , " fullname= " + getFullName ( ) ) ;
pushFooter ( container ) ;
return container ;
}
std : : string CCellZone : : getFullName ( ) const
{
return std : : string ( getOwner ( ) - > getFullName ( ) + " : " + getName ( ) ) ;
}
IAliasCont * CCellZone : : getAliasCont ( TAIType type )
{
switch ( type )
{
case AITypeCell :
return & _Cells ;
default :
return NULL ;
}
}
CAliasTreeOwner * CCellZone : : createChild ( IAliasCont * cont , CAIAliasDescriptionNode * aliasTree )
{
if ( ! cont )
return NULL ;
CAliasTreeOwner * child = NULL ;
switch ( aliasTree - > getType ( ) )
{
// create the child and adds it to the corresponding position.
case AITypeCell :
child = new CCell ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
}
if ( child )
cont - > addAliasChild ( child ) ;
return child ;
}
bool CCellZone : : findRestAndFoodFaunaZoneInCellList ( CFaunaZone const * & rest , CPropertySet const & restActivity , CFaunaZone const * & food , CPropertySet const & foodActivity , std : : vector < CCell * > const & cells , TAStarFlag const denyflags )
{
static bool extensiveDebug = false ; // That extensive debug has code 0001
if ( extensiveDebug ) nldebug ( " ED0001.01: restActivity=%s foodActivity=%s " , restActivity . toString ( ) . c_str ( ) , foodActivity . toString ( ) . c_str ( ) ) ;
// Flags topology
typedef CHashMap < uint , CCellChoice > TSearchMapCellChoice ;
typedef CHashMap < uint , TSearchMapCellChoice > TSearchMap ;
TSearchMap searchMap ;
const float minimumScore = /*28*28*/ 24 * 24 ; // :FIXME: Put that in a config thing (like a config file)
// Property sets for all activities
CPropertySet activities [ CCellChoice : : MAX_ZONE_SCORE ] ;
activities [ CCellChoice : : FOOD_ZONE_SCORE ] . merge ( foodActivity ) ;
activities [ CCellChoice : : REST_ZONE_SCORE ] . merge ( restActivity ) ;
// Look for a conveninent zone in a convenient cell.
if ( extensiveDebug ) nldebug ( " ED0001.02: cells.size()=%d " , cells . size ( ) ) ;
// For each cell
FOREACHC ( itCell , std : : vector < CCell * > , cells )
{
CCell const * const cell = * itCell ;
if ( ! cell )
continue ;
if ( extensiveDebug ) nldebug ( " ED0001.03: cell->faunaZonesCst().size()=%d " , cell - > faunaZonesCst ( ) . size ( ) ) ;
// For each zone
FOREACHC ( itFaunaZone , CCont < CFaunaZone > , cell - > faunaZonesCst ( ) )
{
CFaunaZone const * const faunaZone = * itFaunaZone ;
# ifdef NL_DEBUG
nlassert ( faunaZone ) ;
# endif
// For each activity
for ( uint32 typeZone = 0 ; typeZone < CCellChoice : : MAX_ZONE_SCORE ; + + typeZone )
{
// Get zone position
CWorldPosition const & wpos = faunaZone - > worldValidPos ( ) ;
// Check it's valid
if ( ! wpos . isValid ( ) )
{
if ( extensiveDebug ) nldebug ( " ED0001.04: !wpos.isValid() " ) ;
continue ;
}
// tmp nico for debug
/*
static bool displayActivities = false ;
if ( displayActivities )
{
nlinfo ( " Zone activities " ) ;
const AITYPES : : CPropertySet & ps = faunaZone - > additionalActivities ( ) ;
const std : : set < NLMISC : : TStringId > & props = ps . properties ( ) ;
std : : set < NLMISC : : TStringId > : : const_iterator it ;
for ( it = props . begin ( ) ; it ! = props . end ( ) ; + + it )
{
nlinfo ( " Prop = %s " , NLMISC : : CStringMapper : : unmap ( * it ) . c_str ( ) ) ;
}
nlinfo ( " Wanted activities " ) ;
for ( it = activities [ typeZone ] . properties ( ) . begin ( ) ; it ! = activities [ typeZone ] . properties ( ) . end ( ) ; + + it )
{
nlinfo ( " Prop = %s " , NLMISC : : CStringMapper : : unmap ( * it ) . c_str ( ) ) ;
}
}
*/
// Check that zone activity match
if ( ! faunaZone - > haveActivity ( activities [ typeZone ] ) )
{
if ( extensiveDebug ) nldebug ( " ED0001.05: !faunaZone->haveActivity(activities[typeZone]) " ) ;
continue ;
}
TAStarFlag const flags = ( TAStarFlag ) ( wpos . getFlags ( ) & GroundFlags ) ; // Erase unused flags.
float const score = faunaZone - > getFreeAreaScore ( ) ;
for ( TAStarFlag possibleFlag = Nothing ; possibleFlag < = GroundFlags ; possibleFlag = ( TAStarFlag ) ( possibleFlag + 2 ) ) // tricky !! -> to replace with a defined list of flags to checks.
{
const uint32 incompatibilityFlags = possibleFlag & denyflags & GroundFlags ; // Erase unused flags.
if ( incompatibilityFlags )
{
if ( extensiveDebug ) nldebug ( " ED0001.06: incompatibilityFlags " ) ;
continue ;
}
const uint32 masterTopo = wpos . getTopologyRef ( ) . getCstTopologyNode ( ) . getMasterTopo ( possibleFlag ) ;
if ( masterTopo = = ~ 0 )
{
if ( extensiveDebug ) nldebug ( " ED0001.07: masterTopo==~0 " ) ;
continue ;
}
if ( score < minimumScore )
{
if ( extensiveDebug ) nldebug ( " ED0001.08: score<minimumScore " ) ;
continue ;
}
CCellChoice : : CZoneScore & zoneScore = searchMap [ possibleFlag ] [ masterTopo ] . zones [ typeZone ] ;
if ( score < zoneScore . score )
{
if ( extensiveDebug ) nldebug ( " ED0001.09: score<zoneScore.score " ) ;
continue ;
}
if ( score = = zoneScore . score )
{
if ( extensiveDebug ) nldebug ( " ED0001.10: score==zoneScore.score " ) ;
if ( CAIS : : rand16 ( 1 ) = = 0 )
zoneScore . zone = faunaZone ;
}
else
{
if ( extensiveDebug ) nldebug ( " ED0001.11: score!=zoneScore.score " ) ;
zoneScore . score = score ;
zoneScore . zone = faunaZone ;
}
}
}
}
}
// find now the best score :)
{
CCellChoice * selectedCell = NULL ;
float minScore = minimumScore ;
for ( TSearchMap : : iterator flagIt = searchMap . begin ( ) , flagItEnd = searchMap . end ( ) ; flagIt ! = flagItEnd ; + + flagIt )
{
for ( TSearchMapCellChoice : : iterator topoIt = flagIt - > second . begin ( ) , topoItEnd = flagIt - > second . end ( ) ; topoIt ! = topoItEnd ; + + topoIt )
{
if ( extensiveDebug ) nldebug ( " ED0001.12: topoIt->second.getTotalScore()=%g minScore=%g " , topoIt - > second . getTotalScore ( ) , minScore ) ;
float theScore = topoIt - > second . getTotalScore ( ) ;
if ( theScore > minScore )
{
selectedCell = & topoIt - > second ;
minScore = selectedCell - > getTotalScore ( ) ;
}
}
}
if ( selectedCell )
{
rest = selectedCell - > zones [ CCellChoice : : REST_ZONE_SCORE ] . zone ;
food = selectedCell - > zones [ CCellChoice : : FOOD_ZONE_SCORE ] . zone ;
# if !FINAL_VERSION
const RYAI_MAP_CRUNCH : : TAStarFlag restFlags = rest - > worldValidPos ( ) . getTopologyRef ( ) . getCstTopologyNode ( ) . getFlags ( ) ;
const RYAI_MAP_CRUNCH : : TAStarFlag foodFlags = food - > worldValidPos ( ) . getTopologyRef ( ) . getCstTopologyNode ( ) . getFlags ( ) ;
nlassert ( ( restFlags & denyflags ) = = 0 ) ;
nlassert ( ( foodFlags & denyflags ) = = 0 ) ;
# endif
return true ;
}
}
return false ;
}
const CFaunaZone * CCellZone : : lookupFaunaZone ( const CPropertySet & activity , TAStarFlag denyflags , size_t replacementGroupFamilyId )
{
float totalScore = 28 * 28 ;
vector < const CFaunaZone * > candidates ;
// prepare a randomly ordered list of cell.
vector < CCell * > cells ;
for ( CCont < CCell > : : iterator it = _Cells . begin ( ) , itEnd = _Cells . end ( ) ; it ! = itEnd ; + + it )
cells . push_back ( * it ) ;
random_shuffle ( cells . begin ( ) , cells . end ( ) ) ;
// look for a conveninent zone in a convenient cell.
for ( uint c = 0 ; c < cells . size ( ) ; + + c )
{
const CCell * const cell = cells [ c ] ;
if ( ! cell )
continue ;
// look for a zone that support activity.
for ( CCont < CFaunaZone > : : const_iterator it = cell - > faunaZonesCst ( ) . begin ( ) , itEnd = cell - > faunaZonesCst ( ) . end ( ) ; it ! = itEnd ; + + it )
{
const CFaunaZone * const faunaZone = * it ;
# ifdef NL_DEBUG
nlassert ( faunaZone ) ;
# endif
// tmp nico for debug
/*
static bool displayActivities = false ;
if ( displayActivities )
{
nlinfo ( " Zone activities " ) ;
const AITYPES : : CPropertySet & ps = faunaZone - > additionalActivities ( ) ;
const std : : set < NLMISC : : TStringId > & props = ps . properties ( ) ;
std : : set < NLMISC : : TStringId > : : const_iterator it ;
for ( it = props . begin ( ) ; it ! = props . end ( ) ; + + it )
{
nlinfo ( " Prop = %s " , NLMISC : : CStringMapper : : unmap ( * it ) . c_str ( ) ) ;
}
nlinfo ( " Wanted activities num = %d " , ( int ) activity . properties ( ) . size ( ) ) ;
if ( activity . properties ( ) . size ( ) ! = 0 )
{
for ( it = activity . properties ( ) . begin ( ) ; it ! = activity . properties ( ) . end ( ) ; + + it )
{
nlinfo ( " Prop = %s " , NLMISC : : CStringMapper : : unmap ( * it ) . c_str ( ) ) ;
}
}
}
*/
if ( ! faunaZone - > worldValidPos ( ) . isValid ( )
| | ! faunaZone - > haveActivity ( activity ) )
continue ;
// if a replacement GroupFamily was asked, it must be in the zone
if ( replacementGroupFamilyId ! = 0 )
{
if ( ! faunaZone - > isSubstituted ( ) ) continue ;
if ( ! faunaZone - > isSubsitutedForGroupFamily ( replacementGroupFamilyId ) ) continue ;
}
else
{
if ( faunaZone - > isSubstituted ( ) ) continue ; // zone wants a substitution group
}
const RYAI_MAP_CRUNCH : : TAStarFlag flags = faunaZone - > worldValidPos ( ) . getTopologyRef ( ) . getCstTopologyNode ( ) . getFlags ( ) ;
if ( flags & denyflags )
continue ;
const float score = faunaZone - > getFreeAreaScore ( ) ;
if ( score > = totalScore )
{
if ( score = = totalScore )
{
candidates . push_back ( faunaZone ) ;
}
else
{
candidates . clear ( ) ;
candidates . push_back ( faunaZone ) ;
totalScore = score ;
}
}
}
}
if ( candidates . size ( ) > 0 )
2010-05-18 14:53:47 +00:00
return candidates [ CAIS : : rand16 ( ( uint32 ) candidates . size ( ) ) ] ;
2010-05-06 00:08:41 +00:00
return NULL ;
}
struct TLookupLogFilter
{
CPropertySet Properties ;
uint32 Alias ;
bool operator = = ( const TLookupLogFilter & other ) const
{
if ( Alias ! = other . Alias )
return false ;
return Properties = = other . Properties ;
}
bool operator < ( const TLookupLogFilter & other ) const
{
if ( Alias ! = other . Alias )
return Alias < other . Alias ;
return Properties < other . Properties ;
}
} ;
const CNpcZone * CCellZone : : lookupNpcZone ( const CPropertySet & activity , size_t replacementGroupFamilyId )
{
float totalScore = 0 ;
// prepare a randomly ordered list of cell.
vector < CCell * > cells ;
for ( CCont < CCell > : : iterator it = _Cells . begin ( ) , itEnd = _Cells . end ( ) ; it ! = itEnd ; + + it )
cells . push_back ( * it ) ;
random_shuffle ( cells . begin ( ) , cells . end ( ) ) ;
vector < const CNpcZone * > candidates ;
// look for a convenient zone in a convenient cell.
for ( uint c = 0 ; c < cells . size ( ) ; + + c )
{
const CCell * const cell = cells [ c ] ;
if ( ! cell )
continue ;
FOREACHC ( it , TAliasZonePlaceList , cell - > npcZonePlacesCst ( ) )
{
const CNpcZone * npcZone = * it ;
# ifdef NL_DEBUG
nlassert ( npcZone ) ;
# endif
if ( ! activity . empty ( )
& & ! npcZone - > properties ( ) . containsPartOfNotStrict ( activity ) )
continue ;
// if a replacement GroupFamily was asked, it must be in the zone
if ( replacementGroupFamilyId ! = 0 )
{
if ( ! npcZone - > isSubstituted ( ) ) continue ;
if ( ! npcZone - > isSubsitutedForGroupFamily ( replacementGroupFamilyId ) ) continue ;
}
else
{
if ( npcZone - > isSubstituted ( ) ) continue ; // zone wants a substitution group
}
const float score = npcZone - > getFreeAreaScore ( ) ;
if ( score > totalScore )
{
totalScore = score ;
candidates . clear ( ) ;
candidates . push_back ( npcZone ) ;
continue ;
}
if ( score = = totalScore )
candidates . push_back ( npcZone ) ;
}
FOREACHC ( it , TAliasZoneShapeList , cell - > npcZoneShapesCst ( ) )
{
// :FIXME: Same code than above, cut n paste
const CNpcZone * const npcZone = * it ;
# ifdef NL_DEBUG
nlassert ( npcZone ) ;
# endif
if ( ! activity . empty ( )
& & ! npcZone - > properties ( ) . containsPartOfNotStrict ( activity ) )
continue ;
const float score = npcZone - > getFreeAreaScore ( ) ;
if ( score > totalScore )
{
totalScore = score ;
candidates . clear ( ) ;
candidates . push_back ( npcZone ) ;
continue ;
}
if ( score = = totalScore )
candidates . push_back ( npcZone ) ;
}
}
if ( candidates . size ( ) > 0 )
2010-05-18 14:53:47 +00:00
return candidates [ CAIS : : rand16 ( ( uint32 ) candidates . size ( ) ) ] ;
2010-05-06 00:08:41 +00:00
// warning only once
{
static set < TLookupLogFilter > filter ;
TLookupLogFilter lf ;
lf . Properties = activity ;
lf . Alias = getAlias ( ) ;
if ( filter . find ( lf ) = = filter . end ( ) )
{
nlwarning ( " CCellZone::lookupNpcZone can't find zone for activity '%s' in cellZone '%s'%s (display only ONCE) " ,
activity . toString ( ) . c_str ( ) ,
getAliasFullName ( ) . c_str ( ) ,
getAliasString ( ) . c_str ( ) ) ;
filter . insert ( lf ) ;
}
}
return NULL ;
}
const CNpcZone * CCellZone : : lookupNpcZoneByName ( /*const TPopulationFamily &family, */ const std : : string & zoneName )
{
for ( uint i = 0 ; i < _Cells . size ( ) ; + + i )
{
CCell * const cell = _Cells [ i ] ;
if ( ! cell )
continue ;
// if (!cell->_FamilyFlags.containsFamily(family))
// continue;
for ( uint j = 0 ; j < cell - > npcZoneCount ( ) ; + + j )
{
CNpcZone * const zone = cell - > npcZone ( j ) ;
if ( ! zone )
continue ;
if ( zone - > getAliasTreeOwner ( ) . getName ( ) = = zoneName )
{ // ok, we found it !
return zone ;
}
}
}
return NULL ;
}
std : : string CCellZone : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + toString ( " :cz%u " , getChildIndex ( ) ) ;
}
void CCellZone : : rebuildEnergyLevels ( )
{
CCont < CGroupFamily > & groupFamilies = getOwner ( ) - > groupFamilies ( ) ;
{
CPropertySet groupFamiliesNames ;
for ( CCont < CGroupFamily > : : iterator it = groupFamilies . begin ( ) , itEnd = groupFamilies . end ( ) ; it ! = itEnd ; + + it )
groupFamiliesNames . addProperty ( it - > getName ( ) ) ;
for ( CCont < CFamilyBehavior > : : iterator it = _Families . begin ( ) , itEnd = _Families . end ( ) ; it ! = itEnd ; )
{
if ( ! groupFamiliesNames . have ( it - > getName ( ) ) )
{
CCont < CFamilyBehavior > : : iterator last = it ;
+ + it ;
_Families . removeChildByIndex ( last - > getChildIndex ( ) ) ;
continue ;
}
+ + it ;
}
}
for ( CCont < CGroupFamily > : : iterator it = groupFamilies . begin ( ) , itEnd = groupFamilies . end ( ) ; it ! = itEnd ; + + it )
{
CCont < CFamilyBehavior > : : iterator itBehav = _Families . begin ( ) , itBehavEnd = _Families . end ( ) ;
for ( ; itBehav ! = itBehavEnd ; + + itBehav )
{
if ( itBehav - > getName ( ) = = it - > getName ( ) )
break ;
}
if ( itBehav ! = itBehavEnd ) // present ?
continue ;
// else create the missing Behavior.
CSmartPtr < CFamilyBehavior > fb = new CFamilyBehavior ( this , * it ) ;
if ( ! fb - > isFamilyProfileValid ( ) )
{
fb = NULL ;
continue ;
}
fb - > setBaseLevel ( ( uint32 ) ( 0.45 * ( double ) ENERGY_SCALE ) ) ; // forced to 0 at start instead of 0.5 ..
fb - > setEffectiveLevel ( fb - > baseLevel ( ) ) ;
_Families . addChild ( fb ) ;
}
}
// predicate to remove old family manager
class CObsoleteFamilyManagerRemover
{
public :
bool operator ( ) ( CFamilyBehavior * fb ) const
{
nlassert ( fb ) ;
if ( fb - > grpFamily ( ) - > getSubstitutionId ( ) ! = 0 ) // do the state only dynamically added groups
{
// if all managers are empty, then can remove
if ( fb - > mgrNpc ( ) - > isEmpty ( ) & & fb - > mgrFauna ( ) - > isEmpty ( ) )
{
return true ;
}
}
return false ;
}
} ;
void CCellZone : : update ( )
{
H_AUTO ( CellZoneUpdate ) ;
// update all family managers
for ( CCont < CFamilyBehavior > : : iterator it = _Families . begin ( ) , itEnd = _Families . end ( ) ; it ! = itEnd ; + + it )
{
{
H_AUTO ( CellZonesManagersUpdate ) ;
it - > updateManagers ( ) ;
}
{
H_AUTO ( FamiliesUpdate ) ;
if ( it - > needUpdate ( ) )
it - > update ( it - > getDt ( ) ) ;
}
}
// remove old substitution family manager if they are not referenced any more
_Families . getInternalCont ( ) . erase ( std : : remove_if ( _Families . getInternalCont ( ) . begin ( ) , _Families . getInternalCont ( ) . end ( ) , CObsoleteFamilyManagerRemover ( ) ) , _Families . getInternalCont ( ) . end ( ) ) ;
}
void CCellZone : : serviceEvent ( const CServiceEvent & info )
{
CCont < CFamilyBehavior > : : iterator first ( _Families . begin ( ) ) , last ( _Families . end ( ) ) ;
for ( ; first ! = last ; + + first )
{
( * first ) - > serviceEvent ( info ) ;
}
}
const CNpcZone * CCellZone : : lookupNpcZoneScorer ( std : : vector < CCell * > cells , const CZoneScorer & scorer )
{
float totalScore = 0 ;
vector < const CNpcZone * > candidates ;
// look for a convenient zone in a convenient cell.
for ( uint c = 0 ; c < cells . size ( ) ; + + c )
{
const CCell * const cell = cells [ c ] ;
if ( ! cell )
continue ;
FOREACHC ( it , TAliasZonePlaceList , cell - > npcZonePlacesCst ( ) )
{
const CNpcZone * const npcZone = * it ;
# ifdef NL_DEBUG
nlassert ( npcZone ) ;
# endif
const float score = scorer . getScore ( * npcZone ) ;
float const distance = scorer . getParam ( * npcZone ) ;
if ( LogScorerScores & & score > = 0.f )
nldebug ( " Zone: %s - Score: %f - Distance: %f " , npcZone - > getAliasTreeOwner ( ) . getAliasFullName ( ) . c_str ( ) , score , distance ) ;
if ( score < totalScore )
continue ;
if ( score > totalScore )
{
totalScore = score ;
candidates . clear ( ) ;
candidates . push_back ( npcZone ) ;
continue ;
}
candidates . push_back ( npcZone ) ;
}
FOREACHC ( it , TAliasZoneShapeList , cell - > npcZoneShapesCst ( ) )
{
// :FIXME: Same code than above, cut n paste
const CNpcZone * const npcZone = * it ;
# ifdef NL_DEBUG
nlassert ( npcZone ) ;
# endif
const float score = scorer . getScore ( * npcZone ) ;
float const distance = scorer . getParam ( * npcZone ) ;
if ( LogScorerScores & & score > = 0.f )
nldebug ( " Zone: %s - Score: %f - Distance: %f " , npcZone - > getAliasTreeOwner ( ) . getAliasFullName ( ) . c_str ( ) , score , distance ) ;
if ( score < totalScore )
continue ;
if ( score > totalScore )
{
totalScore = score ;
candidates . clear ( ) ;
candidates . push_back ( npcZone ) ;
continue ;
}
candidates . push_back ( npcZone ) ;
}
}
if ( candidates . size ( ) > 0 )
2010-05-18 14:53:47 +00:00
return candidates [ CAIS : : rand16 ( ( uint32 ) candidates . size ( ) ) ] ;
2010-05-06 00:08:41 +00:00
return NULL ;
}
bool CCellZone : : spawn ( )
{
// Spawn families
for ( size_t k = 0 ; k < _Families . size ( ) ; + + k )
{
2010-05-18 14:53:47 +00:00
CFamilyBehavior * familyBehavior = _Families [ ( uint32 ) k ] ;
2010-05-06 00:08:41 +00:00
if ( ! familyBehavior )
continue ;
familyBehavior - > spawn ( ) ;
}
// We should check individual errors, but fake success here :)
return true ;
}
bool CCellZone : : despawn ( )
{
// Despawn families
for ( size_t k = 0 ; k < _Families . size ( ) ; + + k )
{
2010-05-18 14:53:47 +00:00
CFamilyBehavior * familyBehavior = _Families [ ( uint32 ) k ] ;
2010-05-06 00:08:41 +00:00
if ( ! familyBehavior )
continue ;
familyBehavior - > despawn ( ) ;
}
// We should check individual errors, but fake success here :)
return true ;
}
//////////////////////////////////////////////////////////////////////////////
// CCell //
//////////////////////////////////////////////////////////////////////////////
CCell : : CCell ( CCellZone * owner , uint32 alias , const std : : string & name )
: CAliasChild < CCellZone > ( owner , alias , name )
{
}
CCell : : ~ CCell ( )
{
unlinkCell ( ) ;
}
std : : string CCell : : getFullName ( ) const
{
return std : : string ( getOwner ( ) - > getFullName ( ) + " : " + getName ( ) ) ;
}
void CCell : : unlinkCell ( )
{
while ( ! _NeighbourCells . empty ( ) )
{
CCell * c = * ( _NeighbourCells . begin ( ) ) ;
c - > _NeighbourCells . erase ( this ) ;
_NeighbourCells . erase ( _NeighbourCells . begin ( ) ) ;
}
}
IAliasCont * CCell : : getAliasCont ( TAIType type )
{
switch ( type )
{
case AITypeDynFaunaZone :
return & _FaunaZones ;
case AITypeDynNpcZonePlace :
return & _NpcZonePlaces ;
case AITypeDynNpcZoneShape :
return & _NpcZoneShapes ;
case AITypeDynRoad :
return & _Roads ;
default :
return NULL ;
}
}
CNpcZone * CCell : : findNpcZone ( const CAIVector & posInside )
{
// for (CCont<CNpcZone>::iterator itNpcZone=npcZones().begin(), itEndNpcZone=npcZones().end(); itNpcZone!=itEndNpcZone; ++itNpcZone)
FOREACH ( itNpcZone , TAliasZonePlaceList , npcZonePlaces ( ) )
{
if ( ! itNpcZone - > atPlace ( posInside ) )
continue ;
// This zone match the position
return * itNpcZone ;
}
FOREACH ( itNpcZone , TAliasZoneShapeList , npcZoneShapes ( ) )
{
// :FIXME: Same code than above, cut n paste
if ( ! itNpcZone - > atPlace ( posInside ) )
continue ;
// This zone match the position
return * itNpcZone ;
}
return NULL ;
}
CAliasTreeOwner * CCell : : createChild ( IAliasCont * cont , CAIAliasDescriptionNode * aliasTree )
{
if ( ! cont )
return NULL ;
CAliasTreeOwner * child = NULL ;
switch ( aliasTree - > getType ( ) )
{
// create the child and adds it to the corresponding position.
case AITypeDynFaunaZone :
{
CFaunaZone * fzc = new CFaunaZone ( this , aliasTree ) ;
child = fzc ;
}
break ;
case AITypeDynNpcZonePlace :
child = new CNpcZonePlace ( this , aliasTree ) ;
break ;
case AITypeDynNpcZoneShape :
child = new CNpcZoneShape ( this , aliasTree ) ;
break ;
case AITypeDynRoad :
child = new CRoad ( this , aliasTree - > getAlias ( ) , aliasTree - > getName ( ) ) ;
break ;
}
if ( child )
cont - > addAliasChild ( child ) ;
return child ;
}
//////////////////////////////////////////////////////////////////////////////
// //
//////////////////////////////////////////////////////////////////////////////
// data structure for path finding
//****************************************
class TListItem
{
public :
// only for search purpose.
TListItem ( const CNpcZone * const zone )
: _Zone ( zone )
, _MvtCost ( 0 )
, _TargetDist ( 0 )
, _Value ( 0 )
, _Parent ( NULL )
, _Road ( NULL )
{ }
TListItem ( const CNpcZone * const zone , const float & mvtCost , const float & targetDist , const float & value , const CNpcZone * const parent , const CRoad * const road )
: _Zone ( zone )
, _MvtCost ( mvtCost )
, _TargetDist ( targetDist )
, _Value ( value )
, _Parent ( parent )
, _Road ( road )
{ }
const float & value ( ) const
{
return _Value ;
}
const CNpcZone * zone ( ) const
{
return _Zone ;
}
const CNpcZone * parent ( ) const
{
return _Parent ;
}
const CRoad * road ( ) const
{
return _Road ;
}
const float & mvtCost ( ) const
{
return _MvtCost ;
}
private :
const CNpcZone * const _Zone ;
const CNpcZone * const _Parent ;
const CRoad * const _Road ;
float _MvtCost ;
float _TargetDist ;
float _Value ;
} ;
struct TOrderItemOnValue : unary_function < TListItem , bool >
{
bool operator ( ) ( const TListItem & item1 , const TListItem & item2 ) const
{
return item1 . value ( ) < item2 . value ( ) ;
}
} ;
struct TOrderItemOnZone : unary_function < TListItem , bool >
{
bool operator ( ) ( const TListItem & item1 , const TListItem & item2 ) const
{
return item1 . zone ( ) < item2 . zone ( ) ;
}
} ;
class TFindItemOnZone
{
public :
TFindItemOnZone ( const CNpcZone * zone )
: _Zone ( zone )
{ }
bool operator ( ) ( const TListItem & item ) const
{
return item . zone ( ) = = _Zone ;
}
private :
const CNpcZone * _Zone ;
} ;
bool pathFind ( const CNpcZone * const start , const CNpcZone * const end , const CPropertySet & zoneFilter , std : : vector < NLMISC : : CSmartPtr < CRoad > > & path , bool logError )
{
/// check that the start and end are in the same continent.
const CContinent * cont = start - > getOwner ( ) - > getOwner ( ) - > getOwner ( ) - > getOwner ( ) ;
if ( end - > getOwner ( ) - > getOwner ( ) - > getOwner ( ) - > getOwner ( ) ! = cont )
{
nlwarning ( " Searching path for zone in different continent ! " ) ;
return false ;
}
# if !FINAL_VERSION
if ( start = = end )
{
nlwarning ( " trying to find a path between same zone %s " , start - > getAliasTreeOwner ( ) . getAliasFullName ( ) . c_str ( ) ) ;
path . clear ( ) ; // ->leads to an assert in the caller ?
return true ;
}
# endif
multiset < TListItem , TOrderItemOnValue > openList ;
set < TListItem , TOrderItemOnZone > closedList ;
const float localDist = ( float ) ( end - > midPos ( ) - start - > midPos ( ) ) . norm ( ) ;
TListItem li ( start , 0 , localDist , localDist , NULL , NULL ) ;
openList . insert ( li ) ;
do
{
const TListItem bestItem = * openList . begin ( ) ;
openList . erase ( openList . begin ( ) ) ;
closedList . insert ( bestItem ) ;
nlassert ( closedList . find ( bestItem ) ! = closedList . end ( ) ) ;
// check if we are at destination
if ( bestItem . zone ( ) = = end )
{
// yeee! we found the path! build the resulting path
const TListItem * pli = & bestItem ;
while ( pli - > parent ( )
& & pli - > road ( ) )
{
path . push_back ( const_cast < CRoad * > ( pli - > road ( ) ) ) ;
set < TListItem , TOrderItemOnZone > : : iterator it ( closedList . find ( pli - > parent ( ) ) ) ;
if ( it ! = closedList . end ( ) )
pli = & ( * it ) ;
else
{
// look in the open list
multiset < TListItem , TOrderItemOnValue > : : iterator it ( find_if ( openList . begin ( ) , openList . end ( ) , TFindItemOnZone ( pli - > parent ( ) ) ) ) ;
nlassert ( it ! = openList . end ( ) ) ;
pli = & ( * it ) ;
}
}
// make the path in correct order
std : : reverse ( path . begin ( ) , path . end ( ) ) ;
return true ;
}
CNpcZone * const z1 = const_cast < CNpcZone * > ( bestItem . zone ( ) ) ;
FOREACH ( road , vector < CDbgPtr < CRoad > > , z1 - > roads ( ) )
{
CNpcZone * z2 = ( * road ) - > startZone ( ) ;
if ( z2 = = z1 )
{
z2 = ( * road ) - > endZone ( ) ;
if ( z2 = = z1 )
continue ;
}
if ( ! z2
| | closedList . find ( TListItem ( z2 ) ) ! = closedList . end ( )
| | ( z2 ! = end
& & z2 - > properties ( ) . containsPartOfStrict ( zoneFilter ) ) )
{
continue ;
}
const float localDist = ( float ) ( end - > midPos ( ) - z2 - > midPos ( ) ) . norm ( ) ;
// _Length in meters
// _Difficulty between 0 and ??
TListItem li ( z2 , bestItem . mvtCost ( ) + ( * road ) - > getCost ( ) , localDist , localDist + li . mvtCost ( ) , z1 , * road ) ;
// first, check if the zone is already in the open list
multiset < TListItem , TOrderItemOnValue > : : iterator it ( find_if ( openList . begin ( ) , openList . end ( ) , TFindItemOnZone ( z2 ) ) ) ;
if ( it = = openList . end ( ) )
{
//If it isn<73> t on the open list, add it to the open list.
// Make the current square the parent of this square.
// Record the F, G, and H costs of the square.
openList . insert ( li ) ;
}
else
{
// If it is on the open list already, check to see if this path
// to that square is better, using G cost as the measure. A lower
// G cost means that this is a better path. If so, change the parent
// of the square to the current square, and recalculate the G and F
// scores of the square. If you are keeping your open list sorted by F
// score, you may need to resort the list to account for the change.
if ( li . mvtCost ( ) < it - > mvtCost ( ) )
{
openList . erase ( it ) ;
openList . insert ( li ) ;
}
}
}
} while ( ! openList . empty ( ) ) ;
if ( logError )
nlwarning ( " Could't find path from '%s'%s to '%s'%s " ,
start - > getAliasTreeOwner ( ) . getAliasFullName ( ) . c_str ( ) ,
start - > getAliasTreeOwner ( ) . getAliasString ( ) . c_str ( ) ,
end - > getAliasTreeOwner ( ) . getAliasFullName ( ) . c_str ( ) ,
end - > getAliasTreeOwner ( ) . getAliasString ( ) . c_str ( ) ) ;
return false ;
}
//////////////////////////////////////////////////////////////////////////////
// CPopulation //
//////////////////////////////////////////////////////////////////////////////
std : : string CPopulation : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + NLMISC : : toString ( " :po%u " , getChildIndex ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////////
// CRoadTrigger //
//////////////////////////////////////////////////////////////////////////////
std : : string CRoadTrigger : : getIndexString ( ) const
{
return getOwner ( ) - > getIndexString ( ) + NLMISC : : toString ( " :rt%u " , getChildIndex ( ) ) ;
}
CGroupFamily : : CGroupFamily ( CAliasTreeOwner * owner , uint32 alias , std : : string const & name )
: CAliasTreeOwner ( alias , name ) ,
_Owner ( owner ) ,
_ProfileName ( 0 ) ,
_SubstitutionId ( 0 ) ,
_Index ( ~ 0 )
{
}
bool CAIRefPlaceXYR : : atPlace ( CAIEntityPhysical const * entity ) const
{
return _Zone - > atPlace ( entity ) ;
}