1
0
forked from 0ad/0ad
0ad/source/simulation/BaseEntity.cpp

261 lines
7.3 KiB
C++
Raw Normal View History

#include "precompiled.h"
#include "BaseEntity.h"
#include "ObjectManager.h"
#include "CStr.h"
2004-07-08 17:22:09 +02:00
#include "ps/Xeromyces.h"
#include "CLogger.h"
#define LOG_CATEGORY "entity"
CBaseEntity::CBaseEntity()
{
AddProperty( L"tag", &m_Tag, false );
AddProperty( L"parent", (CBaseEntity**)&m_base, false );
AddProperty( L"actions.move.speed", &m_speed );
AddProperty( L"actions.move.turningradius", &m_turningRadius );
AddProperty( L"actor", &m_actorObject );
for( int t = 0; t < EVENT_LAST; t++ )
AddProperty( EventNames[t], &m_EventHandlers[t] );
m_base = NULL;
m_actorObject = NULL;
m_bound_type = CBoundingObject::BOUND_NONE;
m_bound_circle = NULL;
m_bound_box = NULL;
}
CBaseEntity::~CBaseEntity()
{
if( m_bound_box )
delete( m_bound_box );
if( m_bound_circle )
delete( m_bound_circle );
}
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 );
}
else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB )
{
m_bound_box = new CBoundingBox();
m_bound_box->setDimensions( m_base->m_bound_box->getWidth(), m_base->m_bound_box->getHeight() );
}
m_bound_type = m_base->m_bound_type;
}
SetBase( m_base );
}
bool CBaseEntity::loadXML( CStr filename )
{
2004-07-08 17:22:09 +02:00
CXeromyces XeroFile;
if (XeroFile.Load(filename) != PSRETURN_OK)
// Fail
2004-07-08 17:22:09 +02:00
return false;
2004-07-08 17:22:09 +02:00
// Define all the elements and attributes used in the XML file
#define EL(x) int el_##x = XeroFile.getElementID(#x)
#define AT(x) int at_##x = XeroFile.getAttributeID(#x)
// Only the ones we can't load using normal methods.
2004-07-08 17:22:09 +02:00
EL(entity);
EL(script);
2004-07-08 17:22:09 +02:00
EL(footprint);
EL(event);
AT(tag);
AT(parent);
2004-07-08 17:22:09 +02:00
AT(radius);
AT(width);
AT(height);
AT(on);
2004-07-08 17:22:09 +02:00
#undef AT
#undef EL
XMBElement Root = XeroFile.getRoot();
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();
m_Tag = Root.getAttributes().getNamedItem( at_tag );
if( !m_Tag.Length() )
{
LOG( ERROR, LOG_CATEGORY, "CBaseEntity::LoadXML: Tag attribute was not specified in file %s. Load failed.", filename.c_str() );
return( false );
}
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-07-08 17:22:09 +02:00
XMBElement Child = RootChildren.item(i);
unsigned int ChildName = Child.getNodeName();
2004-07-08 17:22:09 +02:00
if( ChildName == el_script )
2004-07-08 17:22:09 +02:00
{
CStr Include = Child.getAttributes().getNamedItem( XeroFile.getAttributeID( "file" ) );
jsval dy;
// TODO: Probably try and determine if this file has already been loaded, and skip it.
if( Include.Length() )
{
CVFSFile IncludeFile;
if( IncludeFile.Load( Include ) != PSRETURN_OK )
{
LOG( WARNING, LOG_CATEGORY, "CBaseEntity::loadXML: Could not load script file %s specified in file %s; ignored.", Include.c_str(), filename.c_str() );
}
else
JS_EvaluateScript( g_ScriptingHost.getContext(), JS_GetGlobalObject( g_ScriptingHost.GetContext() ), (const char*)IncludeFile.GetBuffer(), (int)IncludeFile.GetBufferSize(), Include, 1, &dy );
}
CStr Inline = Child.getText();
if( Inline.Length() )
JS_EvaluateScript( g_ScriptingHost.getContext(), JS_GetGlobalObject( g_ScriptingHost.GetContext() ), Inline.c_str(), (int)Inline.Length(), filename.c_str(), Child.getLineNumber(), &dy );
2004-07-08 17:22:09 +02:00
}
else if (ChildName == el_footprint)
2004-07-08 17:22:09 +02:00
{
if( Child.getAttributes().getNamedItem( at_radius ).length() )
{
// Specifying a circular footprint
if( !m_bound_circle )
m_bound_circle = new CBoundingCircle();
CStrW radius (Child.getAttributes().getNamedItem(at_radius));
m_bound_circle->setRadius( radius.ToFloat() );
m_bound_type = CBoundingObject::BOUND_CIRCLE;
}
else
{
if( !m_bound_box )
m_bound_box = new CBoundingBox();
CStrW width (Child.getAttributes().getNamedItem(at_width));
CStrW height (Child.getAttributes().getNamedItem(at_height));
m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() );
m_bound_type = CBoundingObject::BOUND_OABB;
}
2004-07-08 17:22:09 +02:00
}
else if( ChildName == el_event )
2004-07-08 17:22:09 +02:00
{
// Action...On for consistency with the GUI.
CStrW EventName = CStrW( L"on" ) + (CStrW)Child.getAttributes().getNamedItem( at_on );
CStrW Code = (CStrW)Child.getText();
// Does a property with this name already exist?
for( uint eventID = 0; eventID < EVENT_LAST; eventID++ )
{
if( CStrW( EventNames[eventID] ) == EventName )
{
m_EventHandlers[eventID].Compile( CStrW( filename ) + L"::" + EventName + L" (" + CStrW( Child.getLineNumber() ) + L")", Code );
HasProperty( EventName )->m_Inherited = false;
break;
}
}
2004-07-08 17:22:09 +02:00
}
else
2004-07-08 17:22:09 +02:00
{
XMLLoadProperty( XeroFile, Child, CStrW() );
2004-07-08 17:22:09 +02:00
}
}
return true;
}
void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& Source, CStrW BasePropertyName )
{
// Add a property, put the node text into it.
CStrW PropertyName = BasePropertyName + CStr8( XeroFile.getElementString( Source.getNodeName() ) );
IJSProperty* Existing = HasProperty( PropertyName );
if( Existing )
{
if( !Existing->m_Intrinsic )
LOG( WARNING, LOG_CATEGORY, "CBaseEntity::XMLAddProperty: %s already defined for %s. Property trees will be merged.", PropertyName.c_str(), m_Tag.c_str() );
Existing->Set( ToJSVal<CStrW>( Source.getText() ) );
Existing->m_Inherited = false;
}
else
{
if( !Source.getText().length() )
{
// 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
}
else
AddProperty( PropertyName, Source.getText() );
}
PropertyName += CStrW( L"." );
// 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 );
if( Existing )
{
Existing->Set( ToJSVal<CStrW>( Attribute.Value ) );
Existing->m_Inherited = false;
}
else
AddProperty( AttributeName, Attribute.Value );
}
// 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()
{
AddMethod<jsval, &CBaseEntity::ToString>( "toString", 0 );
CJSObject<CBaseEntity, true>::ScriptingInit( "EntityTemplate" );
}
// Script-bound functions
jsval CBaseEntity::ToString( JSContext* cx, uintN argc, jsval* argv )
{
wchar_t buffer[256];
swprintf( buffer, 256, L"[object EntityTemplate: %ls]", m_Tag.c_str() );
buffer[255] = 0;
utf16string str16(buffer, buffer+wcslen(buffer));
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, str16.c_str() ) ) );
}