2004-06-03 20:38:14 +02:00
# include "precompiled.h"
2004-05-22 01:46:16 +02:00
# include "BaseEntity.h"
# include "ObjectManager.h"
# include "CStr.h"
2005-08-15 01:50:37 +02:00
# include "ps/XML/Xeromyces.h"
2004-05-22 01:46:16 +02:00
2004-10-07 21:23:35 +02:00
# include "CLogger.h"
# define LOG_CATEGORY "entity"
2005-12-29 09:42:44 +01:00
STL_HASH_SET < CStr , CStr_hash_compare > CBaseEntity : : scriptsLoaded ;
2004-06-11 00:24:03 +02:00
CBaseEntity : : CBaseEntity ( )
2004-05-30 04:18:49 +02:00
{
2005-03-30 18:14:19 +02:00
m_base = NULL ;
2006-01-16 11:56:47 +01:00
2004-10-07 21:23:35 +02:00
AddProperty ( L " tag " , & m_Tag , false ) ;
2005-03-30 18:14:19 +02:00
AddProperty ( L " parent " , & m_base , false ) ;
2004-10-07 21:23:35 +02:00
AddProperty ( L " actions.move.speed " , & m_speed ) ;
AddProperty ( L " actions.move.turningradius " , & m_turningRadius ) ;
2006-01-05 07:13:31 +01:00
AddProperty ( L " actions.move.run.speed " , & ( m_run . m_Speed ) ) ;
AddProperty ( L " actions.move.run.rangemin " , & ( m_run . m_MinRange ) ) ;
AddProperty ( L " actions.move.run.range " , & ( m_run . m_MaxRange ) ) ;
2006-01-16 11:56:47 +01:00
AddProperty ( L " actions.move.run.regen_rate " , & m_runRegenRate ) ;
AddProperty ( L " actions.move.run.decay_rate " , & m_runDecayRate ) ;
2005-03-19 12:55:27 +01:00
AddProperty ( L " actor " , & m_actorName ) ;
2004-11-11 08:09:32 +01:00
AddProperty ( L " traits.extant " , & m_extant ) ;
2005-12-15 22:59:48 +01:00
AddProperty ( L " traits.corpse " , & m_corpse ) ;
2005-09-06 21:30:41 +02:00
AddProperty ( L " traits.health.curr " , & m_healthCurr ) ;
2006-01-16 11:56:47 +01:00
AddProperty ( L " traits.health.max " , & m_healthMax ) ;
AddProperty ( L " traits.health.bar_height " , & m_healthBarHeight ) ;
AddProperty ( L " traits.health.bar_size " , & m_healthBarSize ) ;
2006-01-21 12:17:15 +01:00
AddProperty ( L " traits.health.regen_rate " , & m_healthRegenRate ) ;
AddProperty ( L " traits.health.regen_start " , & m_healthRegenStart ) ;
AddProperty ( L " traits.health.decay_rate " , & m_healthDecayRate ) ;
2006-01-16 11:56:47 +01:00
AddProperty ( L " traits.stamina.curr " , & m_staminaCurr ) ;
AddProperty ( L " traits.stamina.max " , & m_staminaMax ) ;
AddProperty ( L " traits.stamina.bar_height " , & m_staminaBarHeight ) ;
AddProperty ( L " traits.stamina.bar_size " , & m_staminaBarSize ) ;
2005-09-14 21:43:16 +02:00
AddProperty ( L " traits.minimap.type " , & m_minimapType ) ;
AddProperty ( L " traits.minimap.red " , & m_minimapR ) ;
AddProperty ( L " traits.minimap.green " , & m_minimapG ) ;
AddProperty ( L " traits.minimap.blue " , & m_minimapB ) ;
2005-09-18 05:47:15 +02:00
AddProperty ( L " traits.anchor.type " , & m_anchorType ) ;
2005-10-09 05:43:03 +02:00
AddProperty ( L " traits.vision.los " , & m_los ) ;
AddProperty ( L " traits.vision.permanent " , & m_permanent ) ;
2006-02-26 10:55:20 +01:00
AddProperty ( L " traits.foundation " , & m_foundation ) ;
2004-10-07 21:23:35 +02:00
for ( int t = 0 ; t < EVENT_LAST ; t + + )
2005-04-22 09:12:55 +02:00
{
AddProperty ( EventNames [ t ] , & m_EventHandlers [ t ] , false ) ;
AddHandler ( t , & m_EventHandlers [ t ] ) ;
}
2004-10-23 16:39:28 +02:00
2004-11-11 08:09:32 +01:00
// Initialize, make life a little easier on the scriptors
2005-05-01 21:09:13 +02:00
m_speed = m_turningRadius = 0.0f ;
2006-02-26 10:55:20 +01:00
m_extant = true ;
m_corpse = CStrW ( ) ;
m_foundation = CStrW ( ) ;
2004-11-11 08:09:32 +01:00
2004-10-07 21:23:35 +02:00
m_bound_type = CBoundingObject : : BOUND_NONE ;
2004-05-30 04:18:49 +02:00
m_bound_circle = NULL ;
m_bound_box = NULL ;
}
2004-05-30 03:57:26 +02:00
CBaseEntity : : ~ CBaseEntity ( )
{
if ( m_bound_box )
delete ( m_bound_box ) ;
if ( m_bound_circle )
delete ( m_bound_circle ) ;
}
2004-10-07 21:23:35 +02:00
void CBaseEntity : : loadBase ( )
{
// Don't bother if we're providing a replacement.
if ( m_bound_type = = CBoundingObject : : BOUND_NONE )
{
if ( m_base - > m_bound_type = = CBoundingObject : : BOUND_CIRCLE )
{
m_bound_circle = new CBoundingCircle ( ) ;
m_bound_circle - > setRadius ( m_base - > m_bound_circle - > m_radius ) ;
2005-05-10 09:13:25 +02:00
m_bound_circle - > setHeight ( m_base - > m_bound_circle - > m_height ) ;
2004-10-07 21:23:35 +02:00
}
else if ( m_base - > m_bound_type = = CBoundingObject : : BOUND_OABB )
{
m_bound_box = new CBoundingBox ( ) ;
2005-05-10 09:13:25 +02:00
m_bound_box - > setDimensions ( m_base - > m_bound_box - > getWidth ( ) , m_base - > m_bound_box - > getDepth ( ) ) ;
m_bound_box - > setHeight ( m_base - > m_bound_box - > m_height ) ;
2004-10-07 21:23:35 +02:00
}
m_bound_type = m_base - > m_bound_type ;
}
SetBase ( m_base ) ;
2005-05-01 21:09:13 +02:00
m_classes . SetParent ( & ( m_base - > m_classes ) ) ;
2005-04-22 09:12:55 +02:00
SetNextObject ( m_base ) ;
2004-10-07 21:23:35 +02:00
}
2005-05-01 21:09:13 +02:00
jsval CBaseEntity : : getClassSet ( )
{
STL_HASH_SET < CStrW , CStrW_hash_compare > : : iterator it ;
it = m_classes . m_Set . begin ( ) ;
CStrW result = * ( it + + ) ;
for ( ; it ! = m_classes . m_Set . end ( ) ; it + + )
result + = L " " + * it ;
return ( ToJSVal ( result ) ) ;
}
void CBaseEntity : : setClassSet ( jsval value )
{
// Get the set that was passed in.
CStr temp = ToPrimitive < CStrW > ( value ) ;
CStr entry ;
m_classes . m_Added . clear ( ) ;
m_classes . m_Removed . clear ( ) ;
while ( true )
{
long brk_sp = temp . Find ( ' ' ) ;
long brk_cm = temp . Find ( ' , ' ) ;
long brk = ( brk_sp = = - 1 ) ? brk_cm : ( brk_cm = = - 1 ) ? brk_sp : ( brk_sp < brk_cm ) ? brk_sp : brk_cm ;
if ( brk = = - 1 )
{
entry = temp ;
}
else
{
entry = temp . GetSubstring ( 0 , brk ) ;
temp = temp . GetSubstring ( brk + 1 , temp . Length ( ) ) ;
}
if ( brk ! = 0 )
{
if ( entry [ 0 ] = = ' - ' )
{
entry = entry . GetSubstring ( 1 , entry . Length ( ) ) ;
if ( entry . Length ( ) )
m_classes . m_Removed . push_back ( entry ) ;
}
else
{
if ( entry [ 0 ] = = ' + ' )
entry = entry . GetSubstring ( 1 , entry . Length ( ) ) ;
if ( entry . Length ( ) )
m_classes . m_Added . push_back ( entry ) ;
}
}
if ( brk = = - 1 ) break ;
}
rebuildClassSet ( ) ;
}
void CBaseEntity : : rebuildClassSet ( )
{
m_classes . Rebuild ( ) ;
InheritorsList : : iterator it ;
for ( it = m_Inheritors . begin ( ) ; it ! = m_Inheritors . end ( ) ; it + + )
( * it ) - > rebuildClassSet ( ) ;
}
2004-05-22 01:46:16 +02:00
bool CBaseEntity : : loadXML ( CStr filename )
{
2004-07-08 17:22:09 +02:00
CXeromyces XeroFile ;
2004-07-29 18:17:21 +02:00
if ( XeroFile . Load ( filename ) ! = PSRETURN_OK )
2004-07-17 19:09:33 +02:00
// Fail
2004-07-08 17:22:09 +02:00
return false ;
2004-05-22 01:46:16 +02:00
2004-07-08 17:22:09 +02:00
// Define all the elements and attributes used in the XML file
2004-07-10 22:33:42 +02:00
# define EL(x) int el_##x = XeroFile.getElementID(#x)
# define AT(x) int at_##x = XeroFile.getAttributeID(#x)
2004-10-07 21:23:35 +02:00
// Only the ones we can't load using normal methods.
2004-07-08 17:22:09 +02:00
EL ( entity ) ;
2004-10-07 21:23:35 +02:00
EL ( script ) ;
EL ( event ) ;
2005-12-15 22:59:48 +01:00
EL ( traits ) ;
EL ( footprint ) ;
EL ( depth ) ;
EL ( height ) ;
EL ( radius ) ;
EL ( width ) ;
2004-10-07 21:23:35 +02:00
AT ( parent ) ;
AT ( on ) ;
2005-03-29 22:50:04 +02:00
AT ( file ) ;
2005-04-15 06:23:33 +02:00
AT ( function ) ;
2004-07-08 17:22:09 +02:00
# undef AT
# undef EL
XMBElement Root = XeroFile . getRoot ( ) ;
2004-10-07 21:23:35 +02:00
if ( Root . getNodeName ( ) ! = el_entity )
{
LOG ( ERROR , LOG_CATEGORY , " CBaseEntity::LoadXML: XML root was not \" Entity \" in file %s. Load failed. " , filename . c_str ( ) ) ;
return ( false ) ;
}
2004-07-08 17:22:09 +02:00
XMBElementList RootChildren = Root . getChildNodes ( ) ;
2005-03-29 22:50:04 +02:00
m_Tag = CStr ( filename ) . AfterLast ( " / " ) . BeforeLast ( " .xml " ) ;
2004-10-07 21:23:35 +02:00
m_Base_Name = Root . getAttributes ( ) . getNamedItem ( at_parent ) ;
2004-07-08 17:22:09 +02:00
for ( int i = 0 ; i < RootChildren . Count ; + + i )
2004-05-22 01:46:16 +02:00
{
2004-07-08 17:22:09 +02:00
XMBElement Child = RootChildren . item ( i ) ;
2005-08-09 17:55:44 +02:00
int ChildName = Child . getNodeName ( ) ;
2004-10-07 21:23:35 +02:00
if ( ChildName = = el_script )
2004-07-08 17:22:09 +02:00
{
2005-03-29 22:50:04 +02:00
CStr Include = Child . getAttributes ( ) . getNamedItem ( at_file ) ;
2004-10-07 21:23:35 +02:00
2005-12-29 09:42:44 +01:00
if ( Include . Length ( ) & & scriptsLoaded . find ( Include ) = = scriptsLoaded . end ( ) )
{
scriptsLoaded . insert ( Include ) ;
g_ScriptingHost . RunScript ( Include ) ;
}
2004-10-07 21:23:35 +02:00
CStr Inline = Child . getText ( ) ;
if ( Inline . Length ( ) )
2005-12-29 09:42:44 +01:00
{
g_ScriptingHost . RunMemScript ( Inline . c_str ( ) , Inline . Length ( ) , filename . c_str ( ) , Child . getLineNumber ( ) ) ;
}
2004-07-08 17:22:09 +02:00
}
2005-12-15 22:59:48 +01:00
else if ( ChildName = = el_traits )
2004-07-08 17:22:09 +02:00
{
2005-12-15 22:59:48 +01:00
XMBElementList TraitChildren = Child . getChildNodes ( ) ;
for ( int j = 0 ; j < TraitChildren . Count ; + + j )
2004-10-07 21:23:35 +02:00
{
2005-12-15 22:59:48 +01:00
XMBElement TraitChild = TraitChildren . item ( j ) ;
int TraitChildName = TraitChild . getNodeName ( ) ;
if ( TraitChildName = = el_footprint )
{
XMBElementList FootprintChildren = TraitChild . getChildNodes ( ) ;
float radius = 0 , height = 0 , width = 0 , depth = 0 ;
bool hadRadius = false , hadDepth = false ;
for ( int k = 0 ; k < FootprintChildren . Count ; + + k )
{
XMBElement FootprintChild = FootprintChildren . item ( k ) ;
int FootprintChildName = FootprintChild . getNodeName ( ) ;
if ( FootprintChildName = = el_radius )
{
hadRadius = true ;
radius = CStrW ( FootprintChild . getText ( ) ) . ToFloat ( ) ;
}
else if ( FootprintChildName = = el_width )
{
width = CStrW ( FootprintChild . getText ( ) ) . ToFloat ( ) ;
}
else if ( FootprintChildName = = el_height )
{
height = CStrW ( FootprintChild . getText ( ) ) . ToFloat ( ) ;
}
else if ( FootprintChildName = = el_depth )
{
hadDepth = true ;
depth = CStrW ( FootprintChild . getText ( ) ) . ToFloat ( ) ;
}
}
if ( hadRadius )
{
// Specifying a circular footprint
if ( ! m_bound_circle )
m_bound_circle = new CBoundingCircle ( ) ;
m_bound_circle - > setRadius ( radius ) ;
m_bound_circle - > setHeight ( height ) ;
m_bound_type = CBoundingObject : : BOUND_CIRCLE ;
}
else if ( hadDepth )
{
2006-02-26 10:55:20 +01:00
// Specifying a rectangular footprint
2005-12-15 22:59:48 +01:00
if ( ! m_bound_box )
m_bound_box = new CBoundingBox ( ) ;
m_bound_box - > setDimensions ( width , depth ) ;
m_bound_box - > setHeight ( height ) ;
m_bound_type = CBoundingObject : : BOUND_OABB ;
}
2006-02-26 10:55:20 +01:00
// Else, entity has no footprint.
2005-12-15 22:59:48 +01:00
}
2004-10-07 21:23:35 +02:00
}
2005-12-15 22:59:48 +01:00
// important so that scripts can see traits
XMLLoadProperty ( XeroFile , Child , CStrW ( ) ) ;
2004-07-08 17:22:09 +02:00
}
2004-10-07 21:23:35 +02:00
else if ( ChildName = = el_event )
2004-07-08 17:22:09 +02:00
{
2004-10-07 21:23:35 +02:00
// Action...On for consistency with the GUI.
2005-03-29 22:50:04 +02:00
CStrW EventName = L " on " + ( CStrW ) Child . getAttributes ( ) . getNamedItem ( at_on ) ;
2004-10-07 21:23:35 +02:00
2005-03-29 22:50:04 +02:00
CStrW Code ( Child . getText ( ) ) ;
2005-05-18 07:32:09 +02:00
utf16string ExternalFunction = Child . getAttributes ( ) . getNamedItem ( at_function ) ;
2005-04-15 06:23:33 +02:00
2004-10-07 21:23:35 +02:00
// Does a property with this name already exist?
for ( uint eventID = 0 ; eventID < EVENT_LAST ; eventID + + )
{
if ( CStrW ( EventNames [ eventID ] ) = = EventName )
{
2005-05-18 07:32:09 +02:00
if ( ExternalFunction ! = utf16string ( ) )
2005-04-15 06:23:33 +02:00
{
jsval fnval ;
2005-05-18 07:32:09 +02:00
JSBool ret = JS_GetUCProperty ( g_ScriptingHost . GetContext ( ) , g_ScriptingHost . GetGlobalObject ( ) , ExternalFunction . c_str ( ) , ExternalFunction . size ( ) , & fnval ) ;
2005-06-28 06:06:25 +02:00
debug_assert ( ret ) ;
2005-04-15 06:23:33 +02:00
JSFunction * fn = JS_ValueToFunction ( g_ScriptingHost . GetContext ( ) , fnval ) ;
if ( ! fn )
{
LOG ( ERROR , LOG_CATEGORY , " CBaseEntity::LoadXML: Function does not exist for event %hs in file %s. Load failed. " , EventName . c_str ( ) , filename . c_str ( ) ) ;
break ;
}
m_EventHandlers [ eventID ] . SetFunction ( fn ) ;
}
else
m_EventHandlers [ eventID ] . Compile ( CStrW ( filename ) + L " :: " + EventName + L " ( " + CStrW ( Child . getLineNumber ( ) ) + L " ) " , Code ) ;
2004-10-07 21:23:35 +02:00
HasProperty ( EventName ) - > m_Inherited = false ;
break ;
}
}
2004-07-08 17:22:09 +02:00
}
2004-10-07 21:23:35 +02:00
else
2004-07-08 17:22:09 +02:00
{
2004-10-07 21:23:35 +02:00
XMLLoadProperty ( XeroFile , Child , CStrW ( ) ) ;
2004-07-08 17:22:09 +02:00
}
2004-10-07 21:23:35 +02:00
}
return true ;
}
2004-10-07 22:49:35 +02:00
void CBaseEntity : : XMLLoadProperty ( const CXeromyces & XeroFile , const XMBElement & Source , CStrW BasePropertyName )
2004-10-07 21:23:35 +02:00
{
// Add a property, put the node text into it.
CStrW PropertyName = BasePropertyName + CStr8 ( XeroFile . getElementString ( Source . getNodeName ( ) ) ) ;
2005-04-22 09:12:55 +02:00
IJSComplexProperty * Existing = HasProperty ( PropertyName ) ;
2004-10-07 21:23:35 +02:00
if ( Existing )
{
if ( ! Existing - > m_Intrinsic )
2005-12-13 09:05:30 +01:00
LOG ( WARNING , LOG_CATEGORY , " CBaseEntity::XMLAddProperty: %ls already defined for %ls. Property trees will be merged. " , PropertyName . c_str ( ) , m_Tag . c_str ( ) ) ;
2005-03-30 18:14:19 +02:00
Existing - > Set ( this , JSParseString ( Source . getText ( ) ) ) ;
2004-10-07 21:23:35 +02:00
Existing - > m_Inherited = false ;
}
else
{
if ( ! Source . getText ( ) . length ( ) )
2004-06-03 15:27:01 +02:00
{
2004-10-07 21:23:35 +02:00
// Arbitrarily say that if a node has no other value, define it to be 'true'.
// Appears to be the most convenient thing to do in most circumstances.
AddProperty ( PropertyName , JSVAL_TRUE ) ;
2004-07-08 17:22:09 +02:00
}
2004-10-07 21:23:35 +02:00
else
2006-02-26 10:55:20 +01:00
{
2004-10-07 21:23:35 +02:00
AddProperty ( PropertyName , Source . getText ( ) ) ;
2006-02-26 10:55:20 +01:00
}
2004-10-07 21:23:35 +02:00
}
2004-06-03 15:27:01 +02:00
2004-10-07 21:23:35 +02:00
PropertyName + = CStrW ( L " . " ) ;
2004-05-22 01:46:16 +02:00
2004-10-07 21:23:35 +02:00
// Retrieve any attributes it has and add them as subproperties.
XMBAttributeList AttributeSet = Source . getAttributes ( ) ;
for ( unsigned int AttributeID = 0 ; AttributeID < ( unsigned int ) AttributeSet . Count ; AttributeID + + )
{
XMBAttribute Attribute = AttributeSet . item ( AttributeID ) ;
CStrW AttributeName = PropertyName + CStr8 ( XeroFile . getAttributeString ( Attribute . Name ) ) ;
Existing = HasProperty ( AttributeName ) ;
2004-11-24 00:56:10 +01:00
2004-10-07 21:23:35 +02:00
if ( Existing )
{
2005-03-30 18:14:19 +02:00
Existing - > Set ( this , JSParseString ( Attribute . Value ) ) ;
2004-10-07 21:23:35 +02:00
Existing - > m_Inherited = false ;
2004-05-22 01:46:16 +02:00
}
2004-10-07 21:23:35 +02:00
else
AddProperty ( AttributeName , Attribute . Value ) ;
}
2004-05-22 01:46:16 +02:00
2004-10-07 21:23:35 +02:00
// Retrieve any child nodes the property has and, similarly, add them as subproperties.
XMBElementList NodeSet = Source . getChildNodes ( ) ;
for ( unsigned int NodeID = 0 ; NodeID < ( unsigned int ) NodeSet . Count ; NodeID + + )
{
XMBElement Node = NodeSet . item ( NodeID ) ;
XMLLoadProperty ( XeroFile , Node , PropertyName ) ;
}
}
/*
Scripting Interface
*/
// Scripting initialization
void CBaseEntity : : ScriptingInit ( )
{
2004-11-24 00:56:10 +01:00
AddMethod < jsval , & CBaseEntity : : ToString > ( " toString " , 0 ) ;
2005-05-18 07:32:09 +02:00
AddClassProperty ( L " traits.id.classes " , ( GetFn ) & CBaseEntity : : getClassSet , ( SetFn ) & CBaseEntity : : setClassSet ) ;
2005-03-30 18:14:19 +02:00
2005-04-22 09:12:55 +02:00
CJSComplex < CBaseEntity > : : ScriptingInit ( " EntityTemplate " ) ;
2004-05-22 01:46:16 +02:00
}
2004-10-07 21:23:35 +02:00
// Script-bound functions
2005-04-22 09:12:55 +02:00
JSObject * CBaseEntity : : GetScriptExecContext ( IEventTarget * target )
{
return ( target - > GetScriptExecContext ( target ) ) ;
}
2005-08-09 17:55:44 +02:00
jsval CBaseEntity : : ToString ( JSContext * cx , uintN UNUSED ( argc ) , jsval * UNUSED ( argv ) )
2004-10-07 21:23:35 +02:00
{
2004-11-07 22:30:47 +01:00
wchar_t buffer [ 256 ] ;
2004-10-07 21:23:35 +02:00
swprintf ( buffer , 256 , L " [object EntityTemplate: %ls] " , m_Tag . c_str ( ) ) ;
buffer [ 255 ] = 0 ;
2004-11-07 22:30:47 +01:00
utf16string str16 ( buffer , buffer + wcslen ( buffer ) ) ;
return ( STRING_TO_JSVAL ( JS_NewUCStringCopyZ ( cx , str16 . c_str ( ) ) ) ) ;
}