2012-05-29 13:31:11 +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 "ai_logic_action.h"
# include "event_reaction_container.h"
# include "state_instance.h"
# include "ai_grp.h"
# include "child_container.h"
# include "server_share/msg_ai_service.h"
# include "ai_share/ai_share.h"
# include "ai_grp_npc.h"
# include "ai_bot_npc.h"
# include "game_share/send_chat.h"
# include "game_share/chat_group.h"
# include "ai_player.h"
# include "nel/misc/debug.h"
# include "nel/misc/sstring.h"
# include "ais_actions.h"
# include "states.h"
# include "continent.h"
# include "continent_inline.h"
# include "script_vm.h"
# include "script_compiler.h"
extern bool simulateBug ( int bugId ) ;
# include "dyn_grp_inline.h"
using namespace std ;
using namespace NLMISC ;
using namespace AITYPES ;
using namespace AICOMP ;
static bool VerboseLog = false ;
# define LOG if (!VerboseLog) {} else nlinfo
//////////////////////////////////////////////////////////////////////////
// Generic Actions
//-------------------------------------------------------------------------------------------
// random_select_state
//-------------------------------------------------------------------------------------------
class CAILogicActionRandomSelectState : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionRandomSelectState ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
_weightSum = 0 ;
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'random_select_state' are ignored " ) ;
for ( uint i = 0 ; i < args . size ( ) ; + + i )
{
std : : string weightStr , stateStr ;
AI_SHARE : : stringToWordAndTail ( args [ i ] , weightStr , stateStr ) ;
sint16 weight ;
NLMISC : : fromString ( weightStr , weight ) ;
if ( weight < = 0
| | NLMISC : : toString ( weight ) ! = weightStr )
{
// nlinfo("no weight found for state in line '%s' - setting weight to 1",args[i].c_str());
stateStr = args [ i ] ;
weight = 1 ;
}
CAIState * state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( stateStr , AITypeNpcStateRoute ) ) ;
if ( ! state )
state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( stateStr , AITypeNpcStateZone ) ) ;
if ( ! state )
{
nlwarning ( " DATA_BUG: EVENT: %s: Failed to identify state: %s " , eventNode - > fullName ( ) . c_str ( ) , args [ i ] . c_str ( ) ) ;
continue ;
}
_states . push_back ( state ) ;
_weights . push_back ( weight ) ;
_weightSum + = weight ;
}
// make sure there's at least one state
if ( _weightSum = = 0 )
nlwarning ( " DATA_BUG: random_select_state: State list is unweighted! " ) ;
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
// make sure something was found
if ( _weightSum = = 0 )
{
nlwarning ( " random_select_state: State list is unweighted! " ) ;
return false ;
}
// generate a random number in range [0.._weightSum) and find a corresponding doofer
sint32 randVal = CAIS : : rand32 ( _weightSum ) ;
uint i ;
for ( i = 0 ; i < _states . size ( ) & & randVal > = _weights [ i ] ; + + i )
randVal - = _weights [ i ] ;
// quick debug test... would be an assert...
# ifdef NL_DEBUG
nlassert ( randVal < = _weights [ i ] ) ; // "BUG: Random value outside random range!"
# endif
entity - > getDebugHistory ( ) - > addHistory ( " GRP State Change: %s => %s " ,
entity - > getState ( ) - > getAliasNode ( ) - > fullName ( ) . c_str ( ) ,
_states [ i ] - > getAliasNode ( ) - > fullName ( ) . c_str ( ) ) ;
entity - > setNextState ( _states [ i ] ) ;
return true ;
}
private :
std : : vector < CDbgPtr < CAIState > > _states ;
std : : vector < sint16 > _weights ;
uint16 _weightSum ;
} ;
//-------------------------------------------------------------------------------------------
// begin_state
//-------------------------------------------------------------------------------------------
class CAILogicActionBeginState : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionBeginState ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'begin_state' are ignored " ) ;
for ( uint i = 0 ; i < args . size ( ) ; + + i )
{
CAIState * state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( args [ i ] , AITypeNpcStateRoute ) ) ;
breakable
{
if ( state )
break ;
state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( args [ i ] , AITypeNpcStateZone ) ) ;
if ( state )
break ;
state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( args [ i ] , AITypeState ) ) ;
if ( state )
break ;
state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( args [ i ] , AITypePunctualState ) ) ;
if ( state )
break ;
nlwarning ( " Action begin_state: failed to identify state: '%s' in '%s' " ,
args [ i ] . c_str ( ) ,
eventNode - > fullName ( ) . c_str ( ) ) ;
continue ;
}
_states . push_back ( state ) ;
}
}
// CPersistentStateInstance
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _states . empty ( ) )
{
nlwarning ( " begin_state failed because state list is empty " ) ;
return false ;
}
uint i = CAIS : : rand16 ( ( uint32 ) _states . size ( ) ) ;
entity - > getDebugHistory ( ) - > addHistory ( " GRP State Change: %s => %s " ,
entity - > getState ( ) - > getAliasNode ( ) - > fullName ( ) . c_str ( ) ,
_states [ i ] - > getAliasNode ( ) - > fullName ( ) . c_str ( ) ) ;
entity - > setNextState ( _states [ i ] ) ;
return true ;
}
private :
std : : vector < CDbgPtr < CAIState > > _states ;
} ;
//-------------------------------------------------------------------------------------------
// user_event
//-------------------------------------------------------------------------------------------
class IAILogicActionUserEvent : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
IAILogicActionUserEvent ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'user_event' are ignored " ) ;
_groupsName = args ;
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _groups . empty ( )
& & ! _groupsName . empty ( ) )
{
// try to retreive the groups
for ( uint i = 0 ; i < _groupsName . size ( ) ; + + i )
{
std : : vector < CGroup * > grps ;
if ( simulateBug ( 4 ) )
{
CAIS : : instance ( ) . AIList ( ) [ 0 ] - > findGroup ( grps , _groupsName [ i ] ) ;
}
else
{
entity - > getGroup ( ) - > getAIInstance ( ) - > findGroup ( grps , _groupsName [ i ] ) ;
}
if ( grps . empty ( ) )
{
nlwarning ( " Can't find group(s) for the name '%s' " , _groupsName [ i ] . c_str ( ) ) ;
continue ;
}
// retreive persistent state instance pointer.
for ( uint j = 0 ; j < grps . size ( ) ; + + j )
_groups . push_back ( grps [ j ] - > getPersistentStateInstance ( ) ) ;
}
// clear the groupName vector to not redo the job
_groupsName . clear ( ) ;
}
if ( _groups . empty ( ) )
{
nlwarning ( " user_event failed because group list is empty " ) ;
return false ;
}
for ( uint i = 0 ; i < _groups . size ( ) ; + + i )
{
CPersistentStateInstance * grp = _groups [ i ] ;
if ( ! grp )
continue ;
grp - > getDebugHistory ( ) - > addHistory ( " GRP User Event: %u " , getIndex ( ) ) ;
nlassert ( getIndex ( ) < 10 ) ;
grp - > processStateEvent ( grp - > getPersistentStateInstance ( ) - > getEventContainer ( ) . EventUserEvent [ getIndex ( ) ] ) ;
}
return true ;
}
protected :
virtual uint32 getIndex ( ) = 0 ;
private :
std : : vector < CPersistentStateInstance * > _groups ;
std : : vector < std : : string > _groupsName ;
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent0 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent0 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) ;
} ;
uint32 CAILogicActionUserEvent0 : : getIndex ( )
{
return 0 ;
}
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent1 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent1 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 1 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent2 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent2 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 2 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent3 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent3 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 3 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent4 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent4 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 4 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent5 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent5 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 5 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent6 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent6 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 6 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent7 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent7 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 7 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent8 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent8 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 8 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionUserEvent9 : public IAILogicActionUserEvent
{
public :
CAILogicActionUserEvent9 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionUserEvent ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 9 ; }
} ;
//-------------------------------------------------------------------------------------------
// multi_action
//-------------------------------------------------------------------------------------------
class CAILogicActionMultiAction : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionMultiAction ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! args . empty ( ) )
nlwarning ( " arguments of 'multi_action' are ignored " ) ;
if ( subActions . empty ( ) )
nlwarning ( " no sub-actions found for multi_action action " ) ;
_subActions = subActions ;
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
// virtual bool executeAction(CAIEntity *entity,const IAIEvent *event)
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _subActions . empty ( ) )
{
nlwarning ( " multi_action failed because sub-action list is empty " ) ;
return false ;
}
bool result = true ;
const uint32 nbActions = ( uint32 ) _subActions . size ( ) ;
for ( uint32 i = 0 ; i < nbActions ; i + + )
{
if ( _subActions [ i ] = = NULL )
{
nlwarning ( " multi actions : _subActions[%d] NULL ! " , i ) ;
}
if ( ! _subActions [ i ] - > executeAction ( entity , event ) )
result = false ;
}
return result ;
}
private :
std : : vector < IAILogicAction : : TSmartPtr > _subActions ;
} ;
//-------------------------------------------------------------------------------------------
// punctual_state
//-------------------------------------------------------------------------------------------
class CAILogicActionPunctualState : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionPunctualState ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'punctual_state' are ignored " ) ;
for ( uint i = 0 ; i < args . size ( ) ; + + i )
{
CAIState * const state = container - > states ( ) . getChildByAlias ( eventNode - > findAliasByNameAndType ( args [ i ] , AITypePunctualState ) ) ;
if ( ! state )
{
nlwarning ( " Failed to identify punctual state: %s " , args [ i ] . c_str ( ) ) ;
continue ;
}
_states . push_back ( state ) ;
}
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _states . empty ( ) )
{
nlwarning ( " begin_punctual_state failed because state list is empty " ) ;
return false ;
}
entity - > setNextPunctualState ( _states [ CAIS : : rand16 ( ( uint32 ) _states . size ( ) ) ] ) ;
entity - > getDebugHistory ( ) - > addHistory ( " GRP BeginPunctual State: %s " ,
entity - > getNextPunctualState ( ) - > getAliasNode ( ) - > fullName ( ) . c_str ( ) ) ;
return true ;
}
private :
std : : vector < CDbgPtr < CAIState > > _states ;
} ;
//-------------------------------------------------------------------------------------------
// punctual_state_end
//-------------------------------------------------------------------------------------------
class CAILogicActionPunctualStateEnd : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionPunctualStateEnd ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'punctual_state_end' are ignored " ) ;
if ( ! args . empty ( ) )
nlwarning ( " args of 'punctual_state_end' are ignored " ) ;
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
entity - > getDebugHistory ( ) - > addHistory ( " GRP End Punctual State: %s " ,
entity - > getPunctualState ( ) - > getAliasNode ( ) - > fullName ( ) . c_str ( ) ) ;
entity - > cancelPunctualState ( ) ;
return true ;
}
} ;
//-------------------------------------------------------------------------------------------
// random_select
//-------------------------------------------------------------------------------------------
class CAILogicActionRandomSelect : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionRandomSelect ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! args . empty ( ) )
nlwarning ( " arguments of 'random_select' are ignored " ) ;
if ( subActions . empty ( ) )
nlwarning ( " no sub-actinos found for random action " ) ;
_subActions = subActions ;
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _subActions . empty ( ) )
{
nlwarning ( " random_select failed because sub-action list is empty " ) ;
return false ;
}
_subActions [ CAIS : : rand16 ( ( uint32 ) _subActions . size ( ) ) ] - > executeAction ( entity , event ) ;
return true ;
}
private :
std : : vector < IAILogicAction : : TSmartPtr > _subActions ;
} ;
//-------------------------------------------------------------------------------------------
// set_state_timeout
//-------------------------------------------------------------------------------------------
class CAILogicActionSetStateTimeout : public IAILogicAction
{
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
CAILogicActionSetStateTimeout ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'set state timeout' are ignored " ) ;
switch ( args . size ( ) )
{
case 2 : NLMISC : : fromString ( args [ 0 ] , _min ) ; if ( args [ 0 ] ! = NLMISC : : toString ( _min ) ) goto BadArgs ;
NLMISC : : fromString ( args [ 1 ] , _max ) ; if ( args [ 1 ] ! = NLMISC : : toString ( _max ) ) goto BadArgs ;
break ;
case 1 : NLMISC : : fromString ( args [ 0 ] , _min ) ; if ( args [ 0 ] ! = NLMISC : : toString ( _min ) ) goto BadArgs ;
_max = _min ;
break ;
default :
BadArgs :
nlwarning ( " Invalid arguments for 'set state timeout' " ) ;
_min = 0 ;
_max = 0 ;
}
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
uint t = _min ;
if ( _min ! = _max )
t + = CAIS : : rand32 ( _max - _min ) ;
entity - > timerStateTimeout ( ) . set ( t ) ;
entity - > getDebugHistory ( ) - > addHistory ( " GRP Set State Timeout: %u " , t ) ;
return true ;
}
private :
uint32 _min , _max ;
} ;
//-------------------------------------------------------------------------------------------
// set_timer_t*
//-------------------------------------------------------------------------------------------
// this class is not instantiated directly. It is derived to refference timers t0,t1,... etc
class IAILogicActionSetTimer : public IAILogicAction
{
enum TTimerMode
{
tm_invalid ,
tm_timer ,
tm_daytime ,
tm_weekday ,
tm_monthday ,
tm_seasonday ,
tm_yearday
} ;
public :
// init is called just after instantiation to give class a chance to parse arguments and
// deal with sub actions
IAILogicActionSetTimer ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
_Mode = tm_invalid ;
_DayTime = 0 ;
_DayNumber = 0 ;
_Min = _Max = 0 ;
if ( ! subActions . empty ( ) )
nlwarning ( " sub-actions of 'set timer' are ignored " ) ;
if ( args . empty ( ) )
{
nlwarning ( " Invalid arguments 'for set_timer' " ) ;
return ;
}
std : : vector < std : : string > strs ;
NLMISC : : explode ( args [ 0 ] , string ( " " ) , strs , true ) ;
if ( strs [ 0 ] = = " day_time " | | strs [ 0 ] = = " daytime " )
{
// this is a day time timer
if ( strs . size ( ) ! = 2 )
{
nlwarning ( " Invalid argument for set timer with daytime(%s) : %s " , args [ 0 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
_Min = _Max = 0 ;
}
else
{
_Mode = tm_daytime ;
_DayTime = parseDayTime ( strs [ 1 ] ) ;
}
}
else if ( strs [ 0 ] = = " week_day " )
{
if ( strs . size ( ) < 2 )
{
nlwarning ( " Missing weekday argument for set timer '%s' : '%s' " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) ) ;
}
_Mode = tm_weekday ;
_DayNumber = atoui ( strs [ 1 ] . c_str ( ) ) ;
if ( strs . size ( ) = = 3 )
_DayTime = parseDayTime ( strs [ 2 ] ) ;
}
else if ( strs [ 0 ] = = " month_day " )
{
if ( strs . size ( ) < 2 )
{
nlwarning ( " Missing monthday argument for set timer '%s' : '%s' " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) ) ;
}
_Mode = tm_monthday ;
_DayNumber = atoui ( strs [ 1 ] . c_str ( ) ) ;
if ( strs . size ( ) = = 3 )
_DayTime = parseDayTime ( strs [ 2 ] ) ;
}
else if ( strs [ 0 ] = = " season_day " )
{
if ( strs . size ( ) < 2 )
{
nlwarning ( " Missing seasonday argument for set timer '%s' : '%s' " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) ) ;
}
_Mode = tm_seasonday ;
_DayNumber = atoui ( strs [ 1 ] . c_str ( ) ) ;
if ( strs . size ( ) = = 3 )
_DayTime = parseDayTime ( strs [ 2 ] ) ;
}
else if ( strs [ 0 ] = = " year_day " )
{
if ( strs . size ( ) < 2 )
{
nlwarning ( " Missing yearday argument for set timer '%s' : '%s' " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) ) ;
}
_Mode = tm_yearday ;
_DayNumber = atoui ( strs [ 1 ] . c_str ( ) ) ;
if ( strs . size ( ) = = 3 )
_DayTime = parseDayTime ( strs [ 2 ] ) ;
}
else
{
_Mode = tm_timer ;
switch ( args . size ( ) )
{
case 2 : NLMISC : : fromString ( args [ 0 ] , _Min ) ; if ( args [ 0 ] ! = NLMISC : : toString ( _Min ) ) goto BadArgs ;
NLMISC : : fromString ( args [ 1 ] , _Max ) ; if ( args [ 1 ] ! = NLMISC : : toString ( _Max ) ) goto BadArgs ;
break ;
case 1 : NLMISC : : fromString ( args [ 0 ] , _Min ) ; if ( args [ 0 ] ! = NLMISC : : toString ( _Min ) ) goto BadArgs ;
_Max = _Min ;
break ;
default :
BadArgs :
nlwarning ( " Invalid arguments for 'set timer'(%s,%s) : %s " ,
( args . size ( ) = = 1 | | args . size ( ) = = 2 ) ? args [ 0 ] . c_str ( ) : " BAD ARG COUNT " ,
( args . size ( ) = = 2 ) ? args [ 1 ] . c_str ( ) : " " ,
eventNode - > fullName ( ) . c_str ( ) ) ;
_Min = 0 ;
_Max = 0 ;
_Mode = tm_invalid ;
}
}
}
float parseDayTime ( const string & param )
{
uint hour ;
uint minute = 0 ;
vector < string > parts ;
explode ( param , string ( " : " ) , parts , false ) ;
if ( parts . size ( ) = = 2 )
minute = NLMISC : : atoui ( parts [ 1 ] . c_str ( ) ) ;
hour = NLMISC : : atoui ( parts [ 0 ] . c_str ( ) ) ;
// convert minute to humdreds of hour to obtain time of day
return hour + ( minute * 100.f ) / ( 60.f * 100.f ) ;
}
// this is the executeAction 'callback' for the action type.
// NOTE: This code should be fast and compact as it may be called very large numbers of times
// depending on the whim of the level designers
virtual bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
// precompute the timer ticks
float currentTime = CTimeInterface : : getRyzomTime ( ) . getRyzomTime ( ) ;
if ( _DayTime < currentTime )
{
// advance to next day
currentTime - = 24 ;
}
float deltaTime = _DayTime - currentTime ;
// convert to ticks
uint32 timeTicks = uint32 ( deltaTime * RYZOM_HOURS_IN_TICKS ) ;
switch ( _Mode )
{
case tm_daytime :
{
_Min = _Max = timeTicks ;
}
break ;
case tm_weekday :
{
uint32 dow = ( uint32 ) CTimeInterface : : getRyzomTime ( ) . getRyzomDayOfWeek ( ) ;
while ( dow < _DayNumber )
dow + = RYZOM_WEEK_IN_DAY ;
_Min = _Max = timeTicks + dow * RYZOM_DAY_IN_TICKS ;
}
break ;
case tm_monthday :
{
uint32 dom = CTimeInterface : : getRyzomTime ( ) . getRyzomDayOfMonth ( ) ;
while ( dom < _DayNumber )
dom + = RYZOM_MONTH_IN_DAY ;
_Min = _Max = timeTicks + dom * RYZOM_DAY_IN_TICKS ;
}
break ;
case tm_seasonday :
{
uint32 dos = CTimeInterface : : getRyzomTime ( ) . getRyzomDayOfSeason ( ) ;
while ( dos < _DayNumber )
dos + = RYZOM_SEASON_IN_DAY ;
_Min = _Max = timeTicks + dos * RYZOM_DAY_IN_TICKS ;
}
break ;
case tm_yearday :
{
uint32 doy = CTimeInterface : : getRyzomTime ( ) . getRyzomDayOfYear ( ) ;
while ( doy < _DayNumber )
doy + = RYZOM_YEAR_IN_DAY ;
_Min = _Max = timeTicks + doy * RYZOM_DAY_IN_TICKS ;
}
break ;
}
uint t = _Min ;
if ( _Max ! = _Min )
t + = CAIS : : rand32 ( _Max - _Min ) ;
entity - > timerUser ( getIndex ( ) ) . set ( t ) ;
entity - > getDebugHistory ( ) - > addHistory ( " GRP Set Timer t%i: %u " , getIndex ( ) , t ) ;
return true ;
}
protected :
virtual uint32 getIndex ( ) = 0 ;
TTimerMode _Mode ;
uint32 _Min ;
uint32 _Max ;
float _DayTime ;
uint32 _DayNumber ;
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSetTimerT0 : public IAILogicActionSetTimer
{
public :
CAILogicActionSetTimerT0 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionSetTimer ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 0 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSetTimerT1 : public IAILogicActionSetTimer
{
public :
CAILogicActionSetTimerT1 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionSetTimer ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 1 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSetTimerT2 : public IAILogicActionSetTimer
{
public :
CAILogicActionSetTimerT2 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionSetTimer ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 2 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSetTimerT3 : public IAILogicActionSetTimer
{
public :
CAILogicActionSetTimerT3 ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container ) :
IAILogicActionSetTimer ( args , subActions , eventNode , container ) { }
protected :
virtual uint32 getIndex ( ) { return 3 ; }
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSpawn : public IAILogicAction
{
public :
CAILogicActionSpawn ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{ }
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
CGroup * grp = entity - > getGroup ( ) ;
if ( grp )
{
if ( grp - > isSpawned ( ) )
grp - > getSpawnObj ( ) - > spawnBots ( ) ;
return true ;
}
else
{
nlwarning ( " CAILogicActionSpawn : entity %s is not a group ? " ,
entity - > aliasTreeOwner ( ) - > getAliasString ( ) . c_str ( ) ) ;
return false ;
}
}
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionDespawn : public IAILogicAction
{
public :
CAILogicActionDespawn ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
_immediately = false ;
// look in args to see if the 'immediately' options is here
if ( args . empty ( ) )
return ;
_immediately = ( args [ 0 ] = = " immediately " ) ;
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
CGroup * const grp = entity - > getGroup ( ) ;
if ( ! grp )
{
nlwarning ( " CAILogicActionDespawn : entity %s is not a group ? " ,
entity - > aliasTreeOwner ( ) - > getAliasString ( ) . c_str ( ) ) ;
return false ;
}
grp - > despawnBots ( _immediately ) ;
return true ;
}
private :
bool _immediately ;
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSendMessage : public IAILogicAction
{
public :
CAILogicActionSendMessage ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( args . empty ( ) )
{
nlwarning ( " CAILogicActionSendMessage need at least a service name ! " ) ;
return ;
}
_destService = args [ 0 ] ;
std : : vector < std : : string > temp ( args . begin ( ) + 1 , args . end ( ) ) ;
_content . swap ( temp ) ;
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _destService . empty ( ) )
return false ;
CCAisActionMsg msg ;
msg . Alias = entity - > aliasTreeOwner ( ) - > getAlias ( ) ;
msg . Content = _content ;
msg . send ( _destService ) ;
return true ;
}
private :
std : : string _destService ;
std : : vector < std : : string > _content ;
} ;
// a big bad global var !
CAIEntityPhysical * TempSpeaker = NULL ;
CBotPlayer * TempPlayer = NULL ;
//-------------------------------------------------------------------------------------------
class CAILogicActionSay : public IAILogicAction
{
public :
CAILogicActionSay ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
_tellToEscort = false ;
if ( args . empty ( ) )
{
nlwarning ( " CAILogicActionSay need a phrase identifier ! " ) ;
return ;
}
std : : string key , tail ;
AI_SHARE : : stringToKeywordAndTail ( args [ 0 ] , key , tail ) ;
breakable
{
if ( key = = " tell " )
{
_type = CChatGroup : : tell ;
break ;
}
if ( key = = " say " )
{
_type = CChatGroup : : say ;
break ;
}
if ( key = = " shout " )
{
_type = CChatGroup : : shout ;
break ;
}
if ( key = = " universe " )
{
_type = CChatGroup : : universe ;
break ;
}
if ( key = = " escort " )
{
_type = CChatGroup : : tell ;
_tellToEscort = true ;
break ;
}
nlwarning ( " Unknow chat mode '%s' ! default to 'say' " , key . c_str ( ) ) ;
_type = CChatGroup : : say ;
// look in the first arg for a channel tag
}
if ( tail . empty ( ) )
{
nlwarning ( " Phrase identifier is empty in action '%s'! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
_phraseId = tail ;
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _phraseId . empty ( ) )
return false ;
// we must first find the group leader, then send a chat message a 'say' mode
const CAIAliasDescriptionNode * const aliasDesc = entity - > aliasTreeOwner ( ) - > getAliasNode ( ) ;
if ( ( aliasDesc & & aliasDesc - > getType ( ) ! = AITypeGrp )
| | ! entity - > getGroup ( ) )
{
nlwarning ( " group can't have 'say' action ! " ) ;
return true ;
}
{
const CSpawnGroup * const grp = entity - > getGroup ( ) - > getSpawnObj ( ) ;
# if !FINAL_VERSION
nlassert ( grp ) ;
# endif
CSpawnBot * bot = NULL ;
if ( TempSpeaker
& & TempSpeaker - > isAlive ( ) )
bot = NLMISC : : safe_cast < CSpawnBot * > ( TempSpeaker ) ;
if ( ! bot )
{
CBot * b = grp - > getPersistent ( ) . getLeader ( ) ;
if ( b )
bot = b - > getSpawnObj ( ) ;
}
if ( ! bot
| | ! bot - > isAlive ( ) )
{
LOG ( " CAILogicActionSay::executeAction : no bots in the group, ignoring action. " ) ;
return true ;
}
// ok, we have the leader, send the chat message.
if ( ! _tellToEscort )
{
if ( _type = = CChatGroup : : tell & & TempPlayer ! = NULL )
{
// tell to the player
LOG ( " CAILogicActionSay::executeAction : sending phrase '%s' to player %s " , _phraseId . c_str ( ) , TempPlayer - > getEntityId ( ) . toString ( ) . c_str ( ) ) ;
npcTellToPlayer ( bot - > dataSetRow ( ) , TempPlayer - > dataSetRow ( ) , _phraseId ) ;
}
else
{
LOG ( " CAILogicActionSay::executeAction : sending phrase '%s' to chat group 'say' " , _phraseId . c_str ( ) ) ;
npcChatToChannel ( bot - > dataSetRow ( ) , _type , _phraseId ) ;
}
}
else
{
// retrieve the team id of the player, then tell to each member of the team.
const uint16 teamId = grp - > getPersistent ( ) . getEscortTeamId ( ) ;
if ( teamId = = CTEAM : : InvalidTeamId )
{
nlwarning ( " CAILogicActionSay::executeAction : can't tell to escort team coz escort is invalid " ) ;
return false ;
}
LOG ( " CAILogicActionSay::executeAction : telling phrase '%s' to escort team %u " , _phraseId . c_str ( ) , teamId ) ;
{
CManagerPlayer * mgr = grp - > getPersistent ( ) . getAIInstance ( ) - > getPlayerMgr ( ) ;
const std : : set < TDataSetRow > team = mgr - > getPlayerTeam ( teamId ) ;
std : : set < TDataSetRow > : : const_iterator first ( team . begin ( ) ) , last ( team . end ( ) ) ;
for ( ; first ! = last ; + + first )
npcTellToPlayer ( bot - > dataSetRow ( ) , * first , _phraseId ) ;
}
}
}
return true ;
}
private :
std : : string _phraseId ;
CChatGroup : : TGroupType _type ;
bool _tellToEscort ;
} ;
//a class to find a group by its name in a state machine,
class CAIGroupFinder
{
public :
static CGroup * findGroup ( const std : : string & groupName , CStateMachine * stateMachine )
{
vector < CGroup * > grps ;
CWorkPtr : : aiInstance ( ) - > findGroup ( grps , groupName ) ;
if ( grps . empty ( ) )
{
nlwarning ( " Can't find group named '%s' " , groupName . c_str ( ) ) ;
return NULL ;
}
if ( grps . size ( ) = = 1 )
{
return grps . front ( ) ;
}
else
{
CGroup * igroup = NULL ;
// Check if theres a group with the good name in the same stateMachine (and only one).
for ( sint32 grpIndex = ( sint32 ) grps . size ( ) - 1 ; grpIndex > = 0 ; grpIndex - - )
{
if ( grps [ grpIndex ] - > getManager ( ) . getStateMachine ( ) ! = stateMachine )
continue ;
if ( igroup )
{
nlwarning ( " More than one group has the name '%s' in the same manager " , groupName . c_str ( ) ) ;
return NULL ;
}
igroup = grps [ grpIndex ] ;
}
if ( ! igroup )
{
nlwarning ( " No group has the name '%s' " , groupName . c_str ( ) ) ;
return NULL ;
}
return igroup ;
}
return NULL ;
}
private :
CAIGroupFinder ( ) ;
} ;
class CAIVariableParser
{
public :
enum TVarType
{
local_variable ,
foreign_variable ,
constant ,
invalid_var_type
} ;
enum TOperator
{
less_than ,
greater_than ,
less_equal ,
greater_equal ,
not_equal ,
equal ,
assign , // WARNING : don't change the relative order of this enumerated constante
add , // they must remain grouped from equal up to div
sub , //
mult , //
div , //
invalid_operator
} ;
struct TVariable
{
TVarType Type ;
CGroup * Group ;
NLMISC : : TStringId VarId ;
// uint32 VarId;
float Value ;
TVariable ( ) :
Type ( invalid_var_type ) ,
Group ( NULL ) ,
// VarId(0),
Value ( 0 )
{ }
} ;
float retreiveValue ( CStateInstance * stateInstance , const TVariable & var )
{
switch ( var . Type )
{
case local_variable :
return stateInstance - > getLogicVar ( var . VarId ) ;
case foreign_variable :
{
CStateInstance * stateInstance = var . Group - > getPersistentStateInstance ( ) ;
return stateInstance - > getLogicVar ( var . VarId ) ;
}
case constant :
return var . Value ;
default :
nlwarning ( " retreiveValue from invalid var type ! returning 0 " ) ;
return 0 ;
}
}
bool evalCondition ( CStateInstance * stateInstance , const TVariable & var1 , TOperator op , const TVariable & var2 )
{
switch ( op )
{
case less_than :
return retreiveValue ( stateInstance , var1 ) < retreiveValue ( stateInstance , var2 ) ;
case greater_than :
return retreiveValue ( stateInstance , var1 ) > retreiveValue ( stateInstance , var2 ) ;
case less_equal :
return retreiveValue ( stateInstance , var1 ) < = retreiveValue ( stateInstance , var2 ) ;
case greater_equal :
return retreiveValue ( stateInstance , var1 ) > = retreiveValue ( stateInstance , var2 ) ;
case equal :
case assign :
return retreiveValue ( stateInstance , var1 ) = = retreiveValue ( stateInstance , var2 ) ;
case not_equal :
return retreiveValue ( stateInstance , var1 ) ! = retreiveValue ( stateInstance , var2 ) ;
}
nlwarning ( " evalCondition invalid operator %u " , op ) ;
return false ;
}
bool parseOperator ( TOperator & op , const string & str )
{
struct TOpName
{
const char * name ;
TOperator op ;
} ;
static TOpName opNames [ ] =
{
{ " < " , less_than } ,
{ " > " , greater_than } ,
{ " <= " , less_equal } ,
{ " >= " , greater_equal } ,
{ " = " , assign } ,
{ " != " , not_equal } ,
{ " <> " , not_equal } ,
{ " == " , equal } ,
{ " + " , add } ,
{ " - " , sub } ,
{ " * " , mult } ,
{ " / " , div }
} ;
const uint32 TABLE_SIZE = sizeof ( opNames ) / sizeof ( TOpName ) ;
for ( uint i = 0 ; i < TABLE_SIZE ; + + i )
{
if ( str ! = opNames [ i ] . name )
continue ;
op = opNames [ i ] . op ;
return true ;
}
op = invalid_operator ;
return false ;
}
// NB : the second parameter in not passed as const reference because it is modified internaly
bool parseVar ( TVariable & var , std : : string str , CStateMachine * stateMachine )
{
var . Type = invalid_var_type ;
string : : size_type pos = str . find ( " : " ) ;
if ( pos = = string : : npos )
{
pos = str . find ( " . " ) ;
}
if ( pos ! = string : : npos )
{
// there is a group name, extract it and retreive the group.
var . Type = foreign_variable ;
const string groupName = str . substr ( 0 , pos ) ;
vector < CGroup * > grps ;
CWorkPtr : : aiInstance ( ) - > findGroup ( grps , groupName ) ;
if ( grps . empty ( ) )
{
nlwarning ( " CAIVariableParser can't find group named '%s' " , groupName . c_str ( ) ) ;
var . Type = invalid_var_type ;
return false ;
}
if ( grps . size ( ) = = 1 )
{
var . Group = grps . front ( ) ;
}
else
{
CGroup * igroup = NULL ;
// Check if theres a group with the good name in the same stateMachine (and only one).
for ( sint32 grpIndex = ( sint32 ) grps . size ( ) - 1 ; grpIndex > = 0 ; grpIndex - - )
{
if ( grps [ grpIndex ] - > getManager ( ) . getStateMachine ( ) ! = stateMachine )
continue ;
if ( igroup )
{
nlwarning ( " CAIVariableParser more than one group has the name '%s' in the same manager " , groupName . c_str ( ) ) ;
var . Type = invalid_var_type ;
return false ;
}
igroup = grps [ grpIndex ] ;
}
if ( ! igroup )
{
nlwarning ( " CAIVariableParser more than one group has the name '%s' " , groupName . c_str ( ) ) ;
var . Type = invalid_var_type ;
return false ;
}
var . Group = igroup ;
}
str = str . substr ( pos + 1 ) ;
}
if ( str . empty ( ) )
{
nlwarning ( " CAIVariableParser no char left to read variable id or constante value " ) ;
var . Type = invalid_var_type ;
return false ;
}
2015-01-13 13:11:07 +00:00
// check if it's a number or a var.
//TODO: and negative values ?
2012-05-29 13:31:11 +00:00
if ( ( str [ 0 ] < = ' 9 ' & & str [ 0 ] > = ' 0 ' ) | | ( str [ 0 ] = = ' - ' ) ) // its a number
{
var . Type = constant ;
2015-01-13 18:47:14 +00:00
NLMISC : : fromString ( str , var . Value ) ;
2012-05-29 13:31:11 +00:00
return true ;
}
// if (str[0] == 'v' || str[0] == 'V')
// its a variable.
{
// if (str.size() != 2)
// {
// nlwarning("CAIVariableParser bad string format to read variable index in '%s'. Should be 'vX' (with X in [0-3])", str.c_str());
// var.Type = invalid_var_type;
// return false;
// }
// this is a variable index
if ( var . Type ! = foreign_variable )
var . Type = local_variable ;
var . VarId = CStringMapper : : map ( str ) ;
// var.VarId = str[1] - '0';
// NLMISC::clamp(var.VarId, (uint32)local_variable, (uint32)invalid_var_type);
return true ;
}
// try to parse a constant value
// var.Type = constant;
2016-06-11 14:54:10 +00:00
// double val;
// NLMISC::fromString(str, val);
2012-05-29 13:31:11 +00:00
// var.Value = float(val);
// return true;
}
} ;
//-------------------------------------------------------------------------------------------
// Same as CAILogicActionConditionIf but the condition is evaluated dynamicaly not at loading of primitive(eg primitive 1 modify primitive 2)
class CAILogicActionDynamicIf : public IAILogicAction , public CAIVariableParser
{
public :
CAILogicActionDynamicIf ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( args . empty ( ) )
{
nlwarning ( " condition_if (%s) need arguments ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( subActions . empty ( ) )
{
nlwarning ( " condition_if (%s) need sub action ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
_SubActions = subActions ;
_Args = args ;
//_EventFullName = eventNode->fullName();
if ( ! _Args . empty ( ) )
{
std : : string oldValue = _Args [ _Args . size ( ) - 1 ] ;
_Args [ _Args . size ( ) - 1 ] = std : : string ( " if ( " ) + oldValue + std : : string ( " ){()setConditionSuccess(1);} else { ()setConditionSuccess(0); } " ) ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
// parse the argument string.
if ( _Args . empty ( ) ) { return false ; }
if ( _SubActions . empty ( ) ) { return false ; }
NLMISC : : CSmartPtr < const AIVM : : CByteCode > codePtr = AICOMP : : CCompiler : : getInstance ( ) . compileCode ( _Args , _EventFullName + std : : string ( " :dynamic if " ) ) ;
CAILogicDynamicIfHelper : : setConditionSuccess ( false ) ;
if ( ! codePtr . isNull ( ) )
{
entity - > getPersistentStateInstance ( ) - > interpretCode ( entity , codePtr ) ;
}
if ( CAILogicDynamicIfHelper : : getConditionSuccess ( ) )
{
_SubActions [ 0 ] - > executeAction ( entity , event ) ;
}
else if ( _SubActions . size ( ) = = 2 )
{
_SubActions [ 1 ] - > executeAction ( entity , event ) ;
}
return true ;
}
protected :
CAIVariableParser : : TVariable _Var1 ;
CAIVariableParser : : TOperator _Op ;
CAIVariableParser : : TVariable _Var2 ;
std : : vector < IAILogicAction : : TSmartPtr > _SubActions ;
std : : vector < std : : string > _Args ;
std : : string _EventFullName ;
static bool _Condition ;
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionConditionIf : public IAILogicAction , public CAIVariableParser
{
public :
CAILogicActionConditionIf ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( args . empty ( ) )
{
nlwarning ( " condition_if (%s) need arguments ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( subActions . empty ( ) )
{
nlwarning ( " condition_if (%s) need sub action ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
_subActions = subActions ;
// parse the argument string.
vector < string > strs ;
NLMISC : : explode ( args [ 0 ] , string ( " " ) , strs , true ) ;
if ( strs . size ( ) ! = 3 )
{
nlwarning ( " condition_if (%s) invalid condition format '%s'. Need 3 parts, found %u " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) , strs . size ( ) ) ;
}
if ( ! parseVar ( _Var1 , strs [ 0 ] , container ) )
{
nlwarning ( " condition_if (%s) error parsing var 1 in action '%s' " , strs [ 0 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( ! parseVar ( _Var2 , strs [ 2 ] , container ) )
{
nlwarning ( " condition_if (%s) error parsing var 2 in action '%s' " , strs [ 2 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( ! parseOperator ( _Op , strs [ 1 ] ) )
{
nlwarning ( " condition_if (%s) error parsing operator in action '%s' " , strs [ 1 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( evalCondition ( entity , _Var1 , _Op , _Var2 ) )
{
if ( ! _subActions . empty ( ) )
_subActions [ 0 ] - > executeAction ( entity , event ) ;
}
return true ;
}
protected :
CAIVariableParser : : TVariable _Var1 ;
CAIVariableParser : : TOperator _Op ;
CAIVariableParser : : TVariable _Var2 ;
std : : vector < IAILogicAction : : TSmartPtr > _subActions ;
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionConditionIfElse : public CAILogicActionConditionIf
{
public :
CAILogicActionConditionIfElse ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
: CAILogicActionConditionIf ( args , subActions , eventNode , container )
{
if ( subActions . size ( ) ! = 2 )
{
nlwarning ( " condition_if_else (%s) should have 2 sub action, %u found " , eventNode - > fullName ( ) . c_str ( ) , subActions . size ( ) ) ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( evalCondition ( entity , _Var1 , _Op , _Var2 ) )
{
if ( ! _subActions . empty ( ) )
_subActions [ 0 ] - > executeAction ( entity , event ) ;
}
else if ( _subActions . size ( ) > 1 )
{
_subActions [ 1 ] - > executeAction ( entity , event ) ;
}
return true ;
}
private :
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionModifyVariable : public IAILogicAction , CAIVariableParser
{
public :
CAILogicActionModifyVariable ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
_Op = invalid_operator ;
if ( args . empty ( ) )
{
nlwarning ( " modify_variable (%s) need arguments ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( ! subActions . empty ( ) )
{
nlwarning ( " modify_variable (%s) sub action ignored ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
// parse the argument string.
vector < string > strs ;
NLMISC : : explode ( args [ 0 ] , string ( " " ) , strs , true ) ;
if ( strs . size ( ) ! = 3 )
{
nlwarning ( " modify_variable (%s) : need 3 parts in arg '%s', only found %u " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) , strs . size ( ) ) ;
return ;
}
if ( ! parseVar ( _Var1 , strs [ 0 ] , container ) )
{
nlwarning ( " modify_variable (%s) error parsing var 1 in action '%s' " , strs [ 0 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( _Var1 . Type = = constant )
{
nlwarning ( " modify_variable (%s) left variable can't be a constant. " , eventNode - > fullName ( ) . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( ! parseVar ( _Var2 , strs [ 2 ] , container ) )
{
nlwarning ( " modify_variable (%s) error parsing var 2 in action '%s' " , strs [ 2 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( ! parseOperator ( _Op , strs [ 1 ] ) )
{
nlwarning ( " modify_variable (%s) error parsing operator in action '%s' " , strs [ 1 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( _Op < CAIVariableParser : : assign | | _Op > CAIVariableParser : : div )
{
nlwarning ( " modify_variable (%s) invalid operator %u " , eventNode - > fullName ( ) . c_str ( ) , _Op ) ;
_Op = CAIVariableParser : : invalid_operator ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _Op = = invalid_operator )
return false ;
float value = retreiveValue ( entity , _Var1 ) ;
switch ( _Op )
{
case assign :
value = retreiveValue ( entity , _Var2 ) ;
//nlinfo("retreived value: %f",value);
break ;
case add :
value + = retreiveValue ( entity , _Var2 ) ;
break ;
case sub :
value - = retreiveValue ( entity , _Var2 ) ;
break ;
case mult :
value * = retreiveValue ( entity , _Var2 ) ;
break ;
case div :
value / = retreiveValue ( entity , _Var2 ) ;
break ;
}
if ( _Var1 . Type = = local_variable )
{
entity - > setLogicVar ( _Var1 . VarId , value ) ;
}
else if ( _Var1 . Type = = foreign_variable )
{
if ( _Var1 . Group ! = NULL )
_Var1 . Group - > getPersistentStateInstance ( ) - > setLogicVar ( _Var1 . VarId , value ) ;
}
else
{
nlwarning ( " modify_variable Inconsistent variable 1 type : %u " , _Var1 . Type ) ;
}
return true ;
}
private :
CAIVariableParser : : TVariable _Var1 ;
CAIVariableParser : : TOperator _Op ;
CAIVariableParser : : TVariable _Var2 ;
} ;
//-------------------------------------------------------------------------------------------
class CAILogicActionEmot : public IAILogicAction
{
public :
CAILogicActionEmot ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
2015-12-17 13:35:48 +00:00
uint32 emot = std : : numeric_limits < uint32 > : : max ( ) ;
2012-05-29 13:31:11 +00:00
if ( ! subActions . empty ( ) )
{
nlwarning ( " emot (%s) should not have sub action " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
if ( args . empty ( ) )
{
nlwarning ( " emot (%s) must containts the emot name ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
emot = CAIS : : instance ( ) . getEmotNumber ( args [ 0 ] ) ;
2015-12-17 13:35:48 +00:00
if ( emot = = std : : numeric_limits < uint32 > : : max ( ) )
2012-05-29 13:31:11 +00:00
{
nlwarning ( " emot (%s) unknow emot name : '%s' ! " , eventNode - > fullName ( ) . c_str ( ) , args [ 0 ] . c_str ( ) ) ;
_EmotNumber = MBEHAV : : NUMBER_OF_BEHAVIOURS ;
}
else
{
// offset to emot behavior
_EmotNumber = ( MBEHAV : : EBehaviour ) ( emot + MBEHAV : : EMOTE_BEGIN ) ;
}
_R2 = false ;
// parse the bots filter (if any)
for ( uint i = 1 ; i < args . size ( ) ; + + i )
{
const string & s = args [ i ] ;
if ( s . empty ( ) )
continue ;
if ( isdigit ( s [ 0 ] ) )
{
// extract a bot number
_BotNumber . push_back ( NLMISC : : atoui ( s . c_str ( ) ) ) ;
}
else
{
std : : string str = s ;
string : : size_type pos = str . find ( " : " ) ;
if ( pos ! = string : : npos )
{
const string groupName = str . substr ( 0 , pos ) ;
CGroup * grp = CAIGroupFinder : : findGroup ( groupName , container ) ;
if ( grp = = NULL )
{
nlwarning ( " npc_say (%s) bad group name (%s) ! " , eventNode - > fullName ( ) . c_str ( ) , groupName . c_str ( ) ) ;
return ;
}
_Groups . push_back ( grp ) ;
str = str . substr ( pos + 1 ) ;
_BotNames . push_back ( str ) ;
_R2 = true ;
}
else
{
_BotNames . push_back ( s ) ;
_Groups . push_back ( 0 ) ;
}
}
}
if ( ! _BotNames . empty ( )
& & ! _BotNumber . empty ( ) )
{
nlwarning ( " emot (%) : mixing bot name and bot number is dangerous ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
}
bool executeAction ( CStateInstance * entity , IAIEvent const * event )
{
CGroup * group = entity - > getGroup ( ) ;
if ( _EmotNumber = = MBEHAV : : NUMBER_OF_BEHAVIOURS )
return false ;
vector < CAIEntityPhysical * > eps ;
if ( TempSpeaker
& & TempSpeaker - > getEntityId ( ) . getType ( ) = = group - > getRyzomType ( )
& & safe_cast < CSpawnBot * > ( TempSpeaker ) - > getPersistent ( ) . getOwner ( ) = = group ) // check that the tempSpeaker entitiy is in this group
{
// ok, this is a good 'speaker', it will play the emot
eps . push_back ( TempSpeaker ) ;
// turn it to face the first targeter
CAIEntityPhysical * targeter = TempSpeaker - > firstTargeter ( ) ;
if ( targeter )
safe_cast < CSpawnBot * > ( TempSpeaker ) - > setTheta ( TempSpeaker - > pos ( ) . angleTo ( targeter - > pos ( ) ) ) ;
}
else
{
// r2 mode groupename:botname
if ( _R2 )
{
uint first = 0 , last = ( uint ) _Groups . size ( ) ;
for ( ; first ! = last ; + + first )
{
CGroup * grp = _Groups [ first ] ;
if ( grp = = 0 ) { grp = group ; }
CAliasCont < CBot > const & bots = grp - > bots ( ) ;
if ( bots . size ( ) ! = 0 )
{
CBot * chld = bots . getChildByName ( _BotNames [ first ] ) ;
if ( chld )
{
CAIEntityPhysical * const ep = chld - > getSpawnObj ( ) ;
if ( ep )
{
eps . push_back ( ep ) ;
}
}
}
}
}
// normal behavior botname or id
else
{
for ( uint i = 0 ; i < group - > bots ( ) . size ( ) ; + + i )
{
const CBot * const bot = group - > getBot ( i ) ;
if ( ! bot
| | ! bot - > isSpawned ( ) )
continue ;
CAIEntityPhysical * const ep = bot - > getSpawnObj ( ) ;
if ( ! _BotNames . empty ( ) )
{
const string * name ;
if ( group - > getRyzomType ( ) = = RYZOMID : : npc )
{
CGroupNpc * const grpNpc = safe_cast < CGroupNpc * > ( group ) ;
if ( ! grpNpc - > botsAreNamed ( )
| | bot - > getAliasTreeOwner ( ) = = NULL )
{
name = & grpNpc - > aliasTreeOwner ( ) - > getName ( ) ;
}
else
{
name = & bot - > getAliasTreeOwner ( ) - > getName ( ) ;
}
}
else
{
name = & group - > aliasTreeOwner ( ) - > getName ( ) ;
}
// if not found.
if ( find ( _BotNames . begin ( ) , _BotNames . end ( ) , * name ) = = _BotNames . end ( ) )
continue ;
}
if ( ! _BotNumber . empty ( )
& & find ( _BotNumber . begin ( ) , _BotNumber . end ( ) , i ) = = _BotNumber . end ( ) )
{
continue ;
}
eps . push_back ( ep ) ;
}
}
}
// send message
if ( ! eps . empty ( ) )
{
for ( uint i = 0 ; i < eps . size ( ) ; + + i )
{
NLMISC : : CEntityId entityId = eps [ i ] - > getEntityId ( ) ;
LOG ( " action emot : setting emot %u on bot %s " , _EmotNumber , entityId . toString ( ) . c_str ( ) ) ;
// the filter test passed, apply the emot
NLNET : : CMessage msgout ( " SET_BEHAVIOUR " ) ;
msgout . serial ( entityId ) ;
MBEHAV : : CBehaviour bh ( _EmotNumber ) ;
bh . Data = ( uint16 ) ( CTimeInterface : : gameCycle ( ) ) ;
msgout . serial ( bh ) ;
NLNET : : CUnifiedNetwork : : getInstance ( ) - > send ( " EGS " , msgout ) ;
}
}
else
{
if ( group )
nlwarning ( " action emote for GroupAlias %s Group name %s : no bots can play the emot ! " , group - > getAliasString ( ) . c_str ( ) , group - > getFullName ( ) . c_str ( ) ) ;
else
nlwarning ( " action emote: no bots can play the emot ! " ) ;
}
return true ;
}
private :
MBEHAV : : EBehaviour _EmotNumber ;
// a list of bot names that will play the emot
vector < string > _BotNames ;
vector < CGroup * > _Groups ;
// a list of bot order number that will play the emot
vector < uint32 > _BotNumber ;
bool _R2 ;
} ;
bool CAILogicDynamicIfHelper : : _ConditionSuccess = false ;
void CAILogicActionSitDownHelper : : sitDown ( CGroup * group )
{
// stand up each bots
for ( CCont < CBot > : : iterator it = group - > bots ( ) . begin ( ) , itEnd = group - > bots ( ) . end ( ) ; it ! = itEnd ; + + it )
{
CSpawnBot * const sb = it - > getSpawnObj ( ) ;
if ( ! sb
| | sb - > getMode ( ) = = MBEHAV : : SIT )
continue ;
sb - > setMode ( MBEHAV : : SIT ) ;
}
}
void CAILogicActionSitDownHelper : : standUp ( CGroup * group )
{
// stand up each bots
for ( CCont < CBot > : : iterator it = group - > bots ( ) . begin ( ) , itEnd = group - > bots ( ) . end ( ) ; it ! = itEnd ; + + it )
{
CSpawnBot * const sb = it - > getSpawnObj ( ) ;
if ( ! sb
| | sb - > getMode ( ) ! = MBEHAV : : SIT )
continue ;
sb - > setMode ( MBEHAV : : NORMAL ) ;
}
}
class CAILogicActionSitDown : public IAILogicAction
{
public :
CAILogicActionSitDown ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
if ( ! subActions . empty ( ) )
{
nlwarning ( " sit_down (%s) should not have sub action " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
if ( ! args . empty ( ) )
{
nlwarning ( " sit_down (%s) doesn have parameters, ignoring! " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
CGroup * const group = entity - > getGroup ( ) ;
CAILogicActionSitDownHelper : : sitDown ( group ) ;
return true ;
}
} ;
class CAILogicActionStandUp : public IAILogicAction
{
public :
CAILogicActionStandUp ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
if ( ! subActions . empty ( ) )
{
nlwarning ( " stand_up (%s) should not have sub action " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
if ( ! args . empty ( ) )
{
nlwarning ( " stand_up (%s) doesn have parameters, ignoring! " , eventNode - > fullName ( ) . c_str ( ) ) ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
CGroup * const group = entity - > getGroup ( ) ;
CAILogicActionSitDownHelper : : standUp ( group ) ;
return true ;
}
} ;
class CAILogicActionSetFaunaActivity : public IAILogicAction
{
enum TFaunaActivity
{
fa_rest ,
fa_food ,
fa_invalid
} ;
// dont seems to be ok, Boris, check this code.
TFaunaActivity _Activity ;
public :
CAILogicActionSetFaunaActivity ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
if ( args . empty ( ) )
{
nlwarning ( " set_fauna_activity (%s) : missing activity parameter " , eventNode - > fullName ( ) . c_str ( ) ) ;
_Activity = fa_invalid ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _Activity = = fa_invalid )
return false ;
CGroup * group = entity - > getGroup ( ) ;
if ( group - > getRyzomType ( ) ! = RYZOMID : : creature )
{
nlwarning ( " set_fauna_activity : the group '%s' is not a fauna group ! " ,
group - > getAliasFullName ( ) . c_str ( ) ) ;
return true ;
}
CGrpFauna * grpFauna = safe_cast < CGrpFauna * > ( group ) ;
CGrpFauna : : TPlaces place ;
_Activity = = fa_rest ? place = CGrpFauna : : REST_PLACE : CGrpFauna : : EAT_PLACE ;
// change the state of the fauna group if needed
// lookup for the cycle we want
uint32 i ;
for ( i = 0 ; i < CGrpFauna : : nbCycle ; + + i )
{
if ( grpFauna - > cycles [ i ] . _Place = = place )
break ;
}
if ( i = = CGrpFauna : : nbCycle )
{
nlwarning ( " set_fauna_activity : Can't find fauna activity '%s' in fauna group '%s' " ,
place = = CGrpFauna : : REST_PLACE ? " REST_PLACE " : " EAT_PLACE " ,
grpFauna - > getAliasFullName ( ) . c_str ( ) ) ;
return false ;
}
grpFauna - > getSpawnObj ( ) - > setCurrentCycle ( i ) ;
return true ;
}
} ;
/*
class CAILogicActionOutpostGiverReady : public IAILogicAction
{
public :
CAILogicActionOutpostGiverReady ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
if ( ! args . empty ( ) )
{
nlwarning ( " CAILogicActionOutpostGiverReady : should not have parameters " ) ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
// just find the outpost name in the group name.
CGroup * const group = entity - > getGroup ( ) ;
CSpawnGroupNpc * const spawnGroup = dynamic_cast < CSpawnGroupNpc * > ( static_cast < CSpawnGroup * > ( group - > createSpawnGroup ( ) ) ) ;
if ( ! spawnGroup )
{
nlwarning ( " CAILogicActionOutpostGiverReady : group '%s'%s is not an npc group " ,
group - > getAliasFullName ( ) . c_str ( ) ,
group - > getAliasString ( ) . c_str ( ) ) ;
return false ;
}
const std : : string & groupName = group - > getName ( ) ;
// the group name should be in the format "outpost_<continent>_<outpost_number>_<group_civ>_steward_<continent_short>1_group"
// and we must keep "outpost_<continent>_<number>" for the outpost name
vector < string > parts ;
explode ( groupName , " _ " , parts , false ) ;
if ( parts . size ( ) ! = 7 )
{
nlwarning ( " CAILogicActionOutpostGiverReady: Invalid outpost mission giver '%s', need 'outpost_<continent>_<outpost_number>_<group_civ>_steward_<continent_short>1_group' for " , groupName . c_str ( ) ) ;
nlwarning ( " CAILogicActionOutpostGiverReady: can't process action for group '%s'%s " ,
group - > getAliasFullName ( ) . c_str ( ) ,
group - > getAliasString ( ) . c_str ( ) ) ;
return false ;
}
string outpostName = parts [ 0 ] + " _ " + parts [ 1 ] + " _ " + parts [ 2 ] ;
// retreive the outpost
COutpost * const outpost = COutpost : : getOutpostByName ( outpostName ) ;
if ( ! outpost )
{
nlwarning ( " CAILogicActionOutpostGiverReady : can't find outpost '%s' " , outpostName . c_str ( ) ) ;
return false ;
}
// just call new event, this will spawn the corect npc
outpost - > newEvent ( ) ;
return true ;
}
} ;
*/
//-------------------------------------------------------------------------------------------
//a switch action.
//Parameters : a variable ([group_name:]v{0,1,2,3})
//Optional a list of label '0', '1', '2', 'default'
//execute the subAction at the index equal to the variable value
class CAILogicActionSwitchActions : public IAILogicAction , public CAIVariableParser
{
public :
CAILogicActionSwitchActions ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
// this line treated first ... in case we bomb out in one of the if(...) { ... return; } cases
uint32 nbArgs = ( uint32 ) args . size ( ) ;
if ( nbArgs = = 0 )
{
nlwarning ( " switch_actions (%s) need an argument ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( subActions . empty ( ) )
{
nlwarning ( " switch_actions (%s) need sub actions ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
_SubActions = subActions ;
// parse the argument string.
if ( ! parseVar ( _Var , args [ 0 ] , container ) )
{
nlwarning ( " switch_actions (%s) error parsing var in action '%s' " , args [ 0 ] . c_str ( ) , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
// if size > 1 the other params are labels eg '0' '1' '2' 'default'
if ( nbArgs > 1 )
{
if ( nbArgs < subActions . size ( ) + 1 )
{
nlwarning ( " CAILogicActionSwitchActions : error! not enough weights in parameters ! " ) ;
}
else
{
_Labels . resize ( nbArgs ) ;
for ( uint32 i = 0 ; i < nbArgs - 1 ; + + i )
{
std : : string label = args [ i + 1 ] ;
if ( label = = " default " )
{
_DefaultAction = subActions [ i ] ;
_Labels [ i ] = - 1 ; // the default case eg "default:" -> _Label[?] = -1
}
else
{
sint32 value ;
NLMISC : : fromString ( label , value ) ;
_Labels [ i ] = value ; // the other case eg "case 4:" -> _Label[?] = 4;
}
}
}
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _SubActions . empty ( ) ) { return true ; }
uint32 val = static_cast < uint32 > ( retreiveValue ( entity , _Var ) ) ;
IAILogicAction : : TSmartPtr action ;
if ( _Labels . empty ( ) )
{
if ( val > = _SubActions . size ( ) )
{
return false ;
}
action = _SubActions [ val ] ;
}
else
{
//look in the labels the action corresponding the Value
action = 0 ;
for ( uint i = 0 ; i < _Labels . size ( ) & & ! action ; + + i )
{
if ( _Labels [ i ] ! = - 1 & & static_cast < uint32 > ( _Labels [ i ] ) = = val )
{
action = _SubActions [ i ] ;
}
}
//not found so use the default value
if ( ! action ) { action = _DefaultAction ; }
}
BOMB_IF ( ! action , " ERROR: Bad action pointer! " , return false ) ;
return action - > executeAction ( entity , event ) ;
}
protected :
CAIVariableParser : : TVariable _Var ;
std : : vector < IAILogicAction : : TSmartPtr > _SubActions ;
std : : vector < sint32 > _Labels ;
IAILogicAction : : TSmartPtr _DefaultAction ;
} ;
class CPropertyZone
: public CRefCount
{
public :
typedef NLMISC : : CSmartPtr < CPropertyZone > TSmartPtr ;
CPropertyZone ( )
: _Shape ( true ) ,
_Target ( CTmpPropertyZone : : All )
{
}
virtual ~ CPropertyZone ( )
{
}
CShape _Shape ;
CPropertySet _Properties ;
CTmpPropertyZone : : TTarget _Target ;
} ;
class CZoneMarker
: public NLMISC : : CVirtualRefCount
{
public :
CZoneMarker ( CAIInstance * aiInstance ,
const std : : vector < CPropertyZone : : TSmartPtr > & zones ,
CAliasCont < CGroupFamily > * substitutionGroupFamily ,
size_t substitutionId
)
: _AiInstance ( aiInstance )
, _Zones ( zones )
, _SubstitutionId ( substitutionId )
{
// add activities flags.
# if !FINAL_VERSION
nlassert ( ! _AiInstance . isNULL ( ) ) ;
# endif
if ( substitutionGroupFamily )
{
_SubstitutionGroupFamilies = * substitutionGroupFamily ;
if ( ! _SubstitutionGroupFamilies . isEmpty ( ) )
{
std : : sort ( _SubstitutionGroupFamilies . getInternalCont ( ) . begin ( ) , _SubstitutionGroupFamilies . getInternalCont ( ) . end ( ) /*, std::less<CSmartPtr<CGroupFamily> >*/ ) ;
// must sort because we're gonna use set_union later
for ( uint k = 0 ; k < _SubstitutionGroupFamilies . size ( ) ; + + k )
{
nlassert ( _SubstitutionGroupFamilies [ k ] ! = NULL ) ;
nlassert ( substitutionId ! = 0 ) ;
_SubstitutionGroupFamilies [ k ] - > setSubstitutionId ( substitutionId ) ;
}
}
}
parseCell ( true ) ;
}
virtual ~ CZoneMarker ( )
{
// remove activities flags.
parseCell ( false ) ;
_AiInstance = ( CAIInstance * ) NULL ;
}
private :
void parseCell ( bool setFlag ) ;
size_t getId ( ) const
{
return ( size_t ) this ;
}
CDbgPtr < CAIInstance > _AiInstance ;
const std : : vector < CPropertyZone : : TSmartPtr > & _Zones ;
CAliasCont < CGroupFamily > _SubstitutionGroupFamilies ;
size_t _SubstitutionId ;
} ;
void CZoneMarker : : parseCell ( bool setFlag )
{
for ( uint k = 0 ; k < _SubstitutionGroupFamilies . size ( ) ; + + k )
{
nlassert ( _SubstitutionGroupFamilies [ k ] ) ;
if ( setFlag )
{
_SubstitutionGroupFamilies [ k ] - > addZoneMarkerRef ( this ) ;
}
else
{
_SubstitutionGroupFamilies [ k ] - > removeZoneMarkerRef ( this ) ;
}
}
std : : vector < CBaseZone * > bz ;
for ( CCont < CContinent > : : iterator itCont ( _AiInstance - > continents ( ) . begin ( ) ) , itEndCont ( _AiInstance - > continents ( ) . end ( ) ) ; itCont ! = itEndCont ; + + itCont )
{
for ( CCont < CRegion > : : iterator itRegion = itCont - > regions ( ) . begin ( ) , itEndRegion = itCont - > 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 )
{
bz . clear ( ) ;
for ( CCont < CFaunaZone > : : iterator itFaunaZone = itCell - > faunaZones ( ) . begin ( ) , itEndFaunaZone = itCell - > faunaZones ( ) . end ( ) ; itFaunaZone ! = itEndFaunaZone ; + + itFaunaZone )
{
if ( ! itFaunaZone - > worldValidPos ( ) . isValid ( ) )
continue ;
bz . push_back ( * itFaunaZone ) ;
}
for ( uint k = 0 ; k < itCell - > npcZoneCount ( ) ; + + k )
{
if ( ! itCell - > npcZone ( k ) - > worldValidPos ( ) . isValid ( ) )
continue ;
bz . push_back ( itCell - > npcZone ( k ) ) ;
}
for ( std : : vector < CBaseZone * > : : iterator itBaseZone = bz . begin ( ) ; itBaseZone ! = bz . end ( ) ; + + itBaseZone )
{
for ( size_t zoneInd = 0 ; zoneInd < _Zones . size ( ) ; zoneInd + + )
{
CPropertyZone : : TSmartPtr zone = _Zones [ zoneInd ] ;
// see if zone type is ok
if ( zone - > _Target ! = CTmpPropertyZone : : All )
{
if ( zone - > _Target ! = ( * itBaseZone ) - > getZoneType ( ) ) continue ;
}
if ( ! zone - > _Shape . contains ( ( * itBaseZone ) - > worldValidPos ( ) ) )
continue ;
// set or unset flags ..
if ( setFlag )
{
( * itBaseZone ) - > additionalActivities ( ) . merge ( zone - > _Properties , getId ( ) ) ;
if ( _SubstitutionId ! = 0 )
{
// merge with the familyGroup of the region
CAliasCont < CGroupFamily > & grf = itRegion - > groupFamilies ( ) ;
std : : sort ( grf . getInternalCont ( ) . begin ( ) , grf . getInternalCont ( ) . end ( ) ) ;
CAliasCont < CGroupFamily > result ;
std : : set_union ( grf . getInternalCont ( ) . begin ( ) , grf . getInternalCont ( ) . end ( ) ,
_SubstitutionGroupFamilies . getInternalCont ( ) . begin ( ) , _SubstitutionGroupFamilies . getInternalCont ( ) . end ( ) ,
std : : back_inserter ( result . getInternalCont ( ) ) ) ;
grf . swap ( result ) ;
// mark fauna zone to accept this substitution group
( * itBaseZone ) - > addSubstitutionGroupFamilyId ( _SubstitutionId ) ;
}
}
else
{
( * itBaseZone ) - > additionalActivities ( ) . removeProperties ( getId ( ) ) ;
if ( _SubstitutionId ! = 0 )
{
// mark fauna zone to reject this substitution group
( * itBaseZone ) - > removeSubstitutionGroupFamilyId ( _SubstitutionId ) ;
}
}
}
}
}
// rebuild cell zones energy levels if substitution groups where added
// (in order to create missing family behaviour objects)
if ( _SubstitutionId ! = 0 & & setFlag )
{
itCellZone - > rebuildEnergyLevels ( ) ;
}
}
}
}
}
class CAILogicActionSetFlagsOnDynZones : public IAILogicAction
{
public :
CAILogicActionSetFlagsOnDynZones ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
for ( uint32 i = 0 ; i < args . size ( ) ; + + i )
{
_Activities . addProperty ( CPropertyId : : create ( args [ i ] ) ) ; // it->first));
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( ! entity )
return true ;
const CAIState * state = entity - > getActiveState ( ) ;
if ( ! state
| | ! state - > isPositional ( ) )
return true ;
const CAIStatePositional * positionalState = NLMISC : : safe_cast < const CAIStatePositional * > ( state ) ; // good coz of previous check.
// if (!positionalState->shape().hasPatat()) // must have a pattat.
// return true;
IManagerParent * const managerParent = entity - > getGroup ( ) - > getOwner ( ) - > getOwner ( ) ;
CAIInstance * const aiInstance = dynamic_cast < CAIInstance * > ( managerParent ) ;
if ( ! aiInstance )
return true ;
// now, we have to add an objet that marks flag to zones at construction and remove them at destruction.
// and let StateChange take care of removing it when necessary.
const bool haveAPattat = positionalState - > shape ( ) . hasPatat ( ) ;
if ( haveAPattat ) // must have a pattat.
{
const CPropertyZone : : TSmartPtr newZone = new CPropertyZone ( ) ;
newZone - > _Shape = positionalState - > shape ( ) ;
newZone - > _Properties = _Activities ;
_Zones . push_back ( newZone ) ;
}
// retrieve substitution groups from parent
if ( _GroupFamilies . isEmpty ( ) )
{
entity - > addStatePersistentObj ( state , new CZoneMarker ( aiInstance , _Zones , NULL , 0 ) ) ; // remove for instance
}
else
{
entity - > addStatePersistentObj ( state , new CZoneMarker ( aiInstance , _Zones , & _GroupFamilies , ( size_t ) this ) ) ; // remove for instance
}
if ( haveAPattat )
_Zones . pop_back ( ) ;
return true ;
}
void addPropertyZone ( CTmpPropertyZone : : TSmartPtr zone )
{
CPropertyZone : : TSmartPtr newZone = new CPropertyZone ( ) ;
if ( ! newZone - > _Shape . setPatat ( zone - > verticalPos , zone - > points ) )
{
}
newZone - > _Properties = zone - > properties ;
newZone - > _Target = zone - > Target ;
_Zones . push_back ( newZone ) ;
}
virtual void addGroupFamily ( CGroupFamily * grpFam ) { _GroupFamilies . addChild ( grpFam ) ; }
private :
std : : vector < CPropertyZone : : TSmartPtr > _Zones ;
CPropertySet _Activities ;
CAliasCont < CGroupFamily > _GroupFamilies ;
} ;
class CAILogicActionSpawnDynGroup : public IAILogicAction
{
public :
CAILogicActionSpawnDynGroup ( const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
nlwarning ( " loadActionSpawnDynGroup " ) ;
_StateMachine = findParam ( " state_machine " , args ) ;
_DynGroup = findParam ( " dyn_group " , args ) ;
_Where = findParam ( " where " , args ) ;
_Count = findParam ( " count " , args ) ;
}
std : : string findParam ( const std : : string & str , const std : : vector < std : : string > & args )
{
for ( uint32 i = 0 ; i < args . size ( ) ; + + i )
{
const string & argStr = args [ i ] ;
if ( argStr . find ( str ) ! = string : : npos )
{
size_t index = argStr . find_last_of ( " " ) ;
if ( index = = string : : npos
| | ( index + 1 ) > = argStr . size ( ) )
continue ;
index + + ;
return argStr . substr ( index , argStr . size ( ) - index ) ;
}
}
return string ( ) ;
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
nlwarning ( " executeActionSpawnDynGroup " ) ;
if ( ! entity )
return true ;
IManagerParent * const managerParent = entity - > getGroup ( ) - > getOwner ( ) - > getOwner ( ) ;
CAIInstance * const aiInstance = dynamic_cast < CAIInstance * > ( managerParent ) ;
if ( ! aiInstance )
return true ;
const CGroupDesc < CGroupFamily > * groupDesc = NULL ;
const CGroupFamily * groupFamily = NULL ;
// Find Group.
FOREACH ( itCont , CCont < CContinent > , aiInstance - > continents ( ) )
{
FOREACH ( itRegion , CCont < CRegion > , itCont - > regions ( ) )
{
FOREACH ( itFamily , CCont < CGroupFamily > , itRegion - > groupFamilies ( ) )
{
FOREACH ( itGroupDesc , CCont < CGroupDesc < CGroupFamily > > , itFamily - > groupDescs ( ) )
{
if ( itGroupDesc - > getName ( ) = = _DynGroup )
{
groupFamily = & ( * * itFamily ) ;
groupDesc = * itGroupDesc ;
goto groupFound ;
}
}
}
}
}
groupFound :
const CStateMachine * stateMachine = NULL ;
CManager * manager ;
// Find State_Machine.
FOREACH ( itCont , CCont < CManager > , aiInstance - > managers ( ) )
{
if ( itCont - > getName ( ) = = _StateMachine )
{
manager = * itCont ;
break ;
}
}
if ( ! manager )
return true ;
CMgrNpc * const npcManager = dynamic_cast < CMgrNpc * > ( manager ) ;
if ( ! npcManager )
return true ;
stateMachine = manager - > getStateMachine ( ) ;
if ( stateMachine - > cstStates ( ) . size ( ) = = 0 )
stateMachine = NULL ;
std : : vector < CCellZone * > cellZones ;
FOREACH ( itCont , CCont < CContinent > , aiInstance - > continents ( ) )
{
FOREACH ( itRegion , CCont < CRegion > , itCont - > regions ( ) )
{
FOREACH ( itCellZone , CCont < CCellZone > , itRegion - > cellZones ( ) )
{
cellZones . push_back ( * itCellZone ) ;
}
}
}
std : : random_shuffle ( cellZones . begin ( ) , cellZones . end ( ) ) ;
const CNpcZone * spawnZone ;
FOREACH ( itCellZone , vector < CCellZone * > , cellZones )
{
spawnZone = ( * itCellZone ) - > lookupNpcZone ( AITYPES : : CPropertySet ( ) , groupFamily - > getSubstitutionId ( ) ) ;
if ( spawnZone )
break ;
}
// set the npc of the group attackable
// groupDesc->setAttackable(true);
CGroupNpc * grp = groupDesc - > createNpcGroup ( npcManager , spawnZone - > midPos ( ) ) ;
if ( grp )
{
grp - > initDynGrp ( groupDesc , NULL ) ;
grp - > setStartState ( stateMachine - > cstStates ( ) [ 0 ] ) ; // sets the first state.
CSpawnGroupNpc * const spawnGrp = grp - > getSpawnObj ( ) ;
// spawnGrp->activityProfile().setAIProfile(new CGrpProfileDynHarvest(spawnGrp,this,spawnZone,spawnZone));
}
return true ;
}
private :
std : : string _StateMachine ;
std : : string _DynGroup ;
std : : string _Where ;
std : : string _Count ;
} ;
//////////////////////////////////////////////////////////////////////////
// Special Code Action
class CAIAliasDescriptionNode ;
class CStateMachine ;
class CAILogicActionCode : public IAILogicAction
{
public :
CAILogicActionCode (
const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container ) ;
bool executeAction ( CStateInstance * entity , const IAIEvent * event ) ;
NLMISC : : CSmartPtr < const AIVM : : CByteCode > _byteCode ;
} ;
CAILogicActionCode : : CAILogicActionCode ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
nldebug ( " loadActionCode " ) ;
_byteCode = CCompiler : : getInstance ( ) . compileCode ( args , eventNode - > fullName ( ) ) ;
}
bool CAILogicActionCode : : executeAction ( CStateInstance * entity , const IAIEvent * event )
{
entity - > interpretCode ( NULL , _byteCode ) ;
return true ;
}
//
//////////////////////////////////////////////////////////////////////////
// Special outpost action
//class CAIAliasDescriptionNode;
//class CStateMachine;
class CAILogicActionOutpostSendSquadStatus
: public IAILogicAction
{
public :
CAILogicActionOutpostSendSquadStatus (
std : : vector < std : : string > const & args ,
std : : vector < IAILogicAction : : TSmartPtr > const & subActions ,
CAIAliasDescriptionNode const * eventNode ,
CStateMachine * container ) ;
bool executeAction ( CStateInstance * entity , IAIEvent const * event ) ;
} ;
CAILogicActionOutpostSendSquadStatus : : CAILogicActionOutpostSendSquadStatus (
std : : vector < std : : string > const & args ,
std : : vector < IAILogicAction : : TSmartPtr > const & subActions ,
CAIAliasDescriptionNode const * eventNode ,
CStateMachine * container )
{
}
bool CAILogicActionOutpostSendSquadStatus : : executeAction ( CStateInstance * entity , IAIEvent const * event )
{
CGroup * group = entity - > getGroup ( ) ;
if ( ! group )
{
nlwarning ( " send_outpost_squad_status failed because state instance is not a group " ) ;
return false ;
}
CGroupNpc * npcGrp = dynamic_cast < CGroupNpc * > ( group ) ;
if ( ! npcGrp )
{
nlwarning ( " send_outpost_squad_status failed because group is not a NPC group " ) ;
return false ;
}
CManager * manager = npcGrp - > getOwner ( ) ;
IManagerParent * managerParent = manager - > getOwner ( ) ;
COutpost * outpost = dynamic_cast < COutpost * > ( managerParent ) ;
if ( ! outpost )
{
nlwarning ( " send_outpost_squad_status failed because group manager parent is not an outpost " ) ;
return false ;
}
outpost - > sendOutpostSquadStatus ( npcGrp ) ;
return true ;
}
//
//////////////////////////////////////////////////////////////////////////
// Special outpost action
class CAILogicActionOutpostReportSquadLeaderDeath
: public IAILogicAction
{
public :
CAILogicActionOutpostReportSquadLeaderDeath (
std : : vector < std : : string > const & args ,
std : : vector < IAILogicAction : : TSmartPtr > const & subActions ,
CAIAliasDescriptionNode const * eventNode ,
CStateMachine * container ) ;
bool executeAction ( CStateInstance * entity , IAIEvent const * event ) ;
} ;
CAILogicActionOutpostReportSquadLeaderDeath : : CAILogicActionOutpostReportSquadLeaderDeath (
std : : vector < std : : string > const & args ,
std : : vector < IAILogicAction : : TSmartPtr > const & subActions ,
CAIAliasDescriptionNode const * eventNode ,
CStateMachine * container )
{
}
bool CAILogicActionOutpostReportSquadLeaderDeath : : executeAction ( CStateInstance * entity , IAIEvent const * event )
{
CGroup * group = entity - > getGroup ( ) ;
if ( ! group )
{
nlwarning ( " outpost_report_squad_leader_death failed because state instance is not a group " ) ;
return false ;
}
CGroupNpc * npcGrp = dynamic_cast < CGroupNpc * > ( group ) ;
if ( ! npcGrp )
{
nlwarning ( " outpost_report_squad_leader_death failed because group is not a NPC group " ) ;
return false ;
}
CManager * manager = npcGrp - > getOwner ( ) ;
IManagerParent * managerParent = manager - > getOwner ( ) ;
COutpost * outpost = dynamic_cast < COutpost * > ( managerParent ) ;
if ( ! outpost )
{
nlwarning ( " outpost_report_squad_leader_death failed because group manager parent is not an outpost " ) ;
return false ;
}
outpost - > squadLeaderDied ( npcGrp ) ;
return true ;
}
//
//////////////////////////////////////////////////////////////////////////
// Special outpost action
class CAILogicActionOutpostReportSquadDeath
: public IAILogicAction
{
public :
CAILogicActionOutpostReportSquadDeath (
std : : vector < std : : string > const & args ,
std : : vector < IAILogicAction : : TSmartPtr > const & subActions ,
CAIAliasDescriptionNode const * eventNode ,
CStateMachine * container ) ;
bool executeAction ( CStateInstance * entity , IAIEvent const * event ) ;
} ;
CAILogicActionOutpostReportSquadDeath : : CAILogicActionOutpostReportSquadDeath (
std : : vector < std : : string > const & args ,
std : : vector < IAILogicAction : : TSmartPtr > const & subActions ,
CAIAliasDescriptionNode const * eventNode ,
CStateMachine * container )
{
}
bool CAILogicActionOutpostReportSquadDeath : : executeAction ( CStateInstance * entity , IAIEvent const * event )
{
CGroup * group = entity - > getGroup ( ) ;
if ( ! group )
{
nlwarning ( " outpost_report_squad_death failed because state instance is not a group " ) ;
return false ;
}
CGroupNpc * npcGrp = dynamic_cast < CGroupNpc * > ( group ) ;
if ( ! npcGrp )
{
nlwarning ( " outpost_report_squad_death failed because group is not a NPC group " ) ;
return false ;
}
CManager * manager = npcGrp - > getOwner ( ) ;
IManagerParent * managerParent = manager - > getOwner ( ) ;
COutpost * outpost = dynamic_cast < COutpost * > ( managerParent ) ;
if ( ! outpost )
{
nlwarning ( " outpost_report_squad_death failed because group manager parent is not an outpost " ) ;
return false ;
}
outpost - > squadDied ( npcGrp ) ;
return true ;
}
//------------------------------------------------------------------
//A say action where it is possible to specify which npc is talking.
//------------------------------------------------------------------
class CAILogicActionNpcSay : public IAILogicAction , public CAIVariableParser
{
public :
CAILogicActionNpcSay ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
_Arg = false ;
if ( args . empty ( ) )
{
nlwarning ( " CAILogicActionNpcSay need a sentence ! " ) ;
return ;
}
if ( ! subActions . empty ( ) )
{
nlwarning ( " npc_say (%s) should not have sub action " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
//no npc specified, (use leader)
if ( args . size ( ) = = 1 )
{
_Npc = " " ;
_Group = NULL ;
_Sentence = args [ 0 ] ;
}
else
//npc specified + string
if ( args . size ( ) > = 2 )
{
std : : string str = args [ 0 ] ;
string : : size_type pos = str . find ( " : " ) ;
if ( pos = = string : : npos )
{
pos = str . find ( " . " ) ;
}
if ( pos ! = string : : npos )
{
const string groupName = str . substr ( 0 , pos ) ;
CGroup * grp = CAIGroupFinder : : findGroup ( groupName , container ) ;
if ( grp = = NULL )
{
nlwarning ( " npc_say (%s) bad group name (%s) ! " , eventNode - > fullName ( ) . c_str ( ) , groupName . c_str ( ) ) ;
return ;
}
_Group = grp ;
str = str . substr ( pos + 1 ) ;
_Npc = str ;
}
else
{
_Group = NULL ;
_Npc = args [ 0 ] ;
}
_Sentence = args [ 1 ] ;
}
/*
//string with variables
else if ( args . size ( ) > = 3 )
{
uint32 i = 2 ;
CAIVariableParser : : TVariable var ;
for ( ; i < args . size ( ) ; + + i )
{
if ( ! parseVar ( var , args [ i ] , container ) )
{
nlwarning ( " Error while parsing variable %s ! " , args [ i ] . c_str ( ) ) ;
return ;
}
nlinfo ( " npc_say use variable <%s> ! " , args [ i ] . c_str ( ) ) ;
_Vars . push_back ( var ) ;
}
_Arg = true ;
} */
else
{
nlwarning ( " <npc_say> error parameters count! " ) ;
}
std : : string cstring = NLMISC : : CSString ( _Sentence ) . left ( 4 ) ;
if ( cstring = = " DSS_ " )
{
_Id = true ;
NLMISC : : CSString tmp = NLMISC : : CSString ( _Sentence ) . right ( ( uint ) _Sentence . length ( ) - 4 ) ;
NLMISC : : CSString tmp2 = tmp . strtok ( " " , false , false , false , false ) ;
_ScenarioId = tmp2 . atoui ( ) ;
_Sentence = tmp ;
nlwarning ( " <npc_say> scenario id : %d string id : %s " , _ScenarioId , _Sentence . c_str ( ) ) ;
}
else
{
_Id = false ;
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
if ( _Sentence = = " " )
{
nlwarning ( " npc has nothing to say! " ) ;
return false ;
}
const CAIAliasDescriptionNode * const aliasDesc = entity - > aliasTreeOwner ( ) - > getAliasNode ( ) ;
if ( aliasDesc - > getType ( ) ! = AITypeGrp
| | ! entity - > getGroup ( ) )
{
nlwarning ( " group can't have 'npc_say' action ! " ) ;
return true ;
}
CGroup * grp ;
if ( _Group = = NULL )
grp = entity - > getGroup ( ) ;
else
grp = _Group ;
CSpawnBot * bot = NULL ;
if ( ! _Npc . empty ( ) )
{
CAliasCont < CBot > const & bots = grp - > bots ( ) ;
if ( bots . size ( ) = = 0 )
{
nlwarning ( " group empty! say nothing! " ) ;
return true ;
}
CBot * chld = bots . getChildByName ( _Npc ) ;
if ( ! chld )
{
std : : string tmp = " no npc named " + _Npc + " ! say nothing! " ;
nlwarning ( tmp . c_str ( ) ) ;
return true ;
}
bot = chld - > getSpawnObj ( ) ;
}
else
{
CBot * b = grp - > getSpawnObj ( ) - > getPersistent ( ) . getLeader ( ) ;
if ( b & & b - > isSpawned ( ) )
{
bot = b - > getSpawnObj ( ) ;
}
}
if ( ! bot | | ! bot - > isAlive ( ) )
{
return true ;
}
if ( ! _Id )
{
ucstring ucstr = _Sentence ;
npcChatToChannelSentence ( bot - > dataSetRow ( ) , CChatGroup : : say , ucstr ) ;
}
else
{
if ( ! _Arg )
{
forwardToDss ( bot - > dataSetRow ( ) , CChatGroup : : say , _Sentence , _ScenarioId ) ;
}
else
{
float val ;
uint32 size = ( uint32 ) _Vars . size ( ) , i = 0 ;
std : : vector < float > values ;
for ( ; i < size ; + + i )
{
val = retreiveValue ( entity , _Vars [ i ] ) ;
values . push_back ( val ) ;
}
forwardToDssArg ( bot - > dataSetRow ( ) , CChatGroup : : say , _Sentence , _ScenarioId , values ) ;
}
}
return true ;
}
private :
std : : string _Sentence ;
uint32 _ScenarioId ;
std : : string _Npc ;
CGroup * _Group ;
bool _Id ;
bool _Arg ;
vector < CAIVariableParser : : TVariable > _Vars ;
} ;
class CAILogicActionNull : public IAILogicAction
{
public :
CAILogicActionNull ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{ }
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{ return true ; }
} ;
//----------------------------------------------------------------------
void CAILogicActionDssStartActHelper : : dssStartAct ( TSessionId sessionId , uint32 actId )
{
NLNET : : CMessage msgout ( " DSS_START_ACT " ) ;
msgout . serial ( sessionId ) ;
msgout . serial ( actId ) ;
NLNET : : CUnifiedNetwork : : getInstance ( ) - > send ( " DSS " , msgout ) ;
}
//----------------------------------------------------------------------
class CAILogicActionFacing : public IAILogicAction
{
public :
CAILogicActionFacing ( const std : : vector < std : : string > & args , const std : : vector < IAILogicAction : : TSmartPtr >
& subActions , const CAIAliasDescriptionNode * eventNode , CStateMachine * container )
{
if ( args . empty ( ) | | args . size ( ) ! = 2 )
{
nlwarning ( " CAILogicActionFacing need two Npc name ! " ) ;
return ;
}
if ( subActions . size ( ) ! = 0 )
{
nlwarning ( " CAILogicActionFacing (%s) should not have any sub action ! " , eventNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
// _facedName = args[1];
for ( uint32 i = 0 ; i < args . size ( ) ; + + i )
{
std : : string name = args [ i ] ;
std : : string str = args [ i ] ;
string : : size_type pos = str . find ( " : " ) ;
if ( pos ! = string : : npos )
{
const string groupName = str . substr ( 0 , pos ) ;
CGroup * grp = CAIGroupFinder : : findGroup ( groupName , container ) ;
if ( grp = = NULL )
{
nlwarning ( " npc_say (%s) bad group name (%s) ! " , eventNode - > fullName ( ) . c_str ( ) , groupName . c_str ( ) ) ;
return ;
}
_FacerGroups . push_back ( grp ) ;
str = str . substr ( pos + 1 ) ;
_FacerNames . push_back ( str ) ;
}
else
{
_FacerGroups . push_back ( NULL ) ;
_FacerNames . push_back ( name ) ;
}
}
}
bool executeAction ( CStateInstance * entity , const IAIEvent * event )
{
CGroup * defaultGrp = entity - > getGroup ( ) ;
CSpawnBot * botFacer = NULL ;
CSpawnBot * botFaced = NULL ;
if ( _FacerNames . size ( ) ! = 2 )
{
nlwarning ( " Warning CAILogicActionFacing: need two Npc name ! " ) ;
return false ;
}
{
CGroup * grp = _FacerGroups [ 0 ] ;
if ( grp = = 0 ) { grp = defaultGrp ; }
CAliasCont < CBot > const & bots = grp - > bots ( ) ;
if ( bots . size ( ) = = 0 )
{
nlwarning ( " Warning CAILogicActionFacing: group empty! unable to face ! " ) ;
return false ;
}
CBot * chld ;
chld = bots . getChildByName ( _FacerNames [ 0 ] ) ;
if ( ! chld )
{
nlwarning ( " Warning CAILogicActionFacing: no npc named %s ! unable to face ! " , _FacerNames [ 0 ] . c_str ( ) ) ;
return false ;
}
botFaced = chld - > getSpawnObj ( ) ;
if ( ! botFaced )
{
return true ;
}
}
{
CGroup * grp = _FacerGroups [ 1 ] ;
if ( grp = = 0 ) { grp = defaultGrp ; }
CAliasCont < CBot > const & bots = grp - > bots ( ) ;
if ( bots . size ( ) = = 0 )
{
nlwarning ( " Warning CAILogicActionFacing: group empty! unable to face ! " ) ;
return false ;
}
CBot * chld ;
chld = bots . getChildByName ( _FacerNames [ 1 ] ) ;
if ( ! chld )
{
nlwarning ( " Warning CAILogicActionFacing: no npc named %s ! unable to face ! " , _FacerNames [ 1 ] . c_str ( ) ) ;
return false ;
}
botFacer = chld - > getSpawnObj ( ) ;
if ( ! botFaced )
{
return true ;
}
}
if ( botFacer & & botFaced )
{
botFacer - > setTheta ( botFacer - > pos ( ) . angleTo ( botFaced - > pos ( ) ) ) ;
}
else
{
return false ;
}
return true ;
}
private :
std : : vector < std : : string > _FacerNames ;
std : : vector < CGroup * > _FacerGroups ;
} ;
//
//////////////////////////////////////////////////////////////////////////
// Generic Actions
//////////////////////////////////////////////////////////////////////////
IAILogicAction * CAIEventReaction : : newAILogicAction ( const char * name ,
const std : : vector < std : : string > & args ,
const std : : vector < IAILogicAction : : TSmartPtr > & subActions ,
const CAIAliasDescriptionNode * eventNode ,
CStateMachine * container )
{
# define BUILD(theName,theClass) if (NLMISC::nlstricmp(theName,name)==0) return new theClass(args,subActions,eventNode,container);
BUILD ( " begin_state " , CAILogicActionBeginState )
BUILD ( " random_select_state " , CAILogicActionRandomSelectState )
BUILD ( " multi_actions " , CAILogicActionMultiAction )
BUILD ( " punctual_state " , CAILogicActionPunctualState )
BUILD ( " punctual_state_end " , CAILogicActionPunctualStateEnd )
BUILD ( " random_select " , CAILogicActionRandomSelect )
BUILD ( " set_state_timeout " , CAILogicActionSetStateTimeout )
BUILD ( " set_timer_t0 " , CAILogicActionSetTimerT0 )
BUILD ( " set_timer_t1 " , CAILogicActionSetTimerT1 )
BUILD ( " set_timer_t2 " , CAILogicActionSetTimerT2 )
BUILD ( " set_timer_t3 " , CAILogicActionSetTimerT3 )
BUILD ( " trigger_event_0 " , CAILogicActionUserEvent0 )
BUILD ( " trigger_event_1 " , CAILogicActionUserEvent1 )
BUILD ( " trigger_event_2 " , CAILogicActionUserEvent2 )
BUILD ( " trigger_event_3 " , CAILogicActionUserEvent3 )
BUILD ( " trigger_event_4 " , CAILogicActionUserEvent4 )
BUILD ( " trigger_event_5 " , CAILogicActionUserEvent5 )
BUILD ( " trigger_event_6 " , CAILogicActionUserEvent6 )
BUILD ( " trigger_event_7 " , CAILogicActionUserEvent7 )
BUILD ( " trigger_event_8 " , CAILogicActionUserEvent8 )
BUILD ( " trigger_event_9 " , CAILogicActionUserEvent9 )
BUILD ( " spawn " , CAILogicActionSpawn )
BUILD ( " despawn " , CAILogicActionDespawn )
BUILD ( " send_message " , CAILogicActionSendMessage )
BUILD ( " say " , CAILogicActionSay )
BUILD ( " npc_say " , CAILogicActionNpcSay )
BUILD ( " facing " , CAILogicActionFacing )
BUILD ( " dynamic_if " , CAILogicActionDynamicIf )
BUILD ( " condition_if " , CAILogicActionConditionIf )
BUILD ( " condition_if_else " , CAILogicActionConditionIfElse )
BUILD ( " modify_variable " , CAILogicActionModifyVariable )
BUILD ( " emot " , CAILogicActionEmot )
BUILD ( " sit_down " , CAILogicActionSitDown )
BUILD ( " stand_up " , CAILogicActionStandUp )
BUILD ( " set_fauna_activity " , CAILogicActionSetFaunaActivity )
// BUILD( "outpost_giver_ready", CAILogicActionOutpostGiverReady )
BUILD ( " set_flags_on_dyn_zones " , CAILogicActionSetFlagsOnDynZones )
BUILD ( " spawn_dyn_group " , CAILogicActionSpawnDynGroup )
BUILD ( " code " , CAILogicActionCode )
BUILD ( " outpost_send_squad_status " , CAILogicActionOutpostSendSquadStatus )
BUILD ( " outpost_report_squad_leader_death " , CAILogicActionOutpostReportSquadLeaderDeath )
BUILD ( " outpost_report_squad_death " , CAILogicActionOutpostReportSquadDeath )
BUILD ( " switch_actions " , CAILogicActionSwitchActions )
BUILD ( " null_action " , CAILogicActionNull )
# undef BUILD
return NULL ;
}
//---------------------------------------------------------------------------------------
// Control over verbose nature of logging
//---------------------------------------------------------------------------------------
NLMISC_COMMAND ( verboseLogicAction , " Turn on or off or check the state of verbose logic action logging " , " " )
{
if ( args . size ( ) > 1 )
return false ;
if ( args . size ( ) = = 1 )
StrToBool ( VerboseLog , args [ 0 ] ) ;
nlinfo ( " VerboseLogging is %s " , VerboseLog ? " ON " : " OFF " ) ;
return true ;
}
# include "event_reaction_include.h"