# Added some groundwork for technologies and fixed some small bugs.
- Entity templates are now per-player, along with an unowned "unmodified" version of each template that should be used to find the original values of the stats. This can be accessed in the scripts as <template>.unmodified. - Fixed a pathfinder crash when the last path from the engine had 0 elements (just ignoring this for now). - Units should no longer become purple when they upgrade in rank. Refs #3. This was SVN commit r3863.
This commit is contained in:
parent
68644fb42b
commit
1e3f5f5d3e
@ -474,7 +474,7 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
debug_warn("Invalid map XML data");
|
||||
}
|
||||
|
||||
CBaseEntity* base = g_EntityTemplateCollection.getTemplate(TemplateName);
|
||||
CBaseEntity* base = g_EntityTemplateCollection.getTemplate( TemplateName, g_Game->GetPlayer(PlayerID) );
|
||||
if (! base)
|
||||
LOG(ERROR, LOG_CATEGORY, "Failed to load entity template '%ls'", TemplateName.c_str());
|
||||
else
|
||||
|
@ -169,20 +169,28 @@ JSBool getEntityByHandle( JSContext* cx, JSObject*, uint argc, jsval* argv, jsva
|
||||
// returns: entity template object
|
||||
JSBool getEntityTemplate( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
REQUIRE_PARAMS(1, getEntityTemplate);
|
||||
REQUIRE_MIN_PARAMS(1, getEntityTemplate);
|
||||
REQUIRE_MAX_PARAMS(2, getEntityTemplate);
|
||||
*rval = JSVAL_NULL;
|
||||
|
||||
CStrW templateName;
|
||||
CPlayer* player = 0;
|
||||
|
||||
try
|
||||
{
|
||||
templateName = g_ScriptingHost.ValueToUCString( argv[0] );
|
||||
if( argc == 2 )
|
||||
{
|
||||
player = ToNative<CPlayer>( argv[1] );
|
||||
}
|
||||
}
|
||||
catch( PSERROR_Scripting_ConversionFailed )
|
||||
{
|
||||
JS_ReportError( cx, "Invalid template identifier" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
CBaseEntity* v = g_EntityTemplateCollection.getTemplate( templateName );
|
||||
|
||||
CBaseEntity* v = g_EntityTemplateCollection.getTemplate( templateName, player );
|
||||
if( !v )
|
||||
{
|
||||
JS_ReportError( cx, "No such template: %s", CStr8(templateName).c_str() );
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
// Add a property (with immediate value)
|
||||
virtual void AddProperty( CStrW PropertyName, jsval Value ) = 0;
|
||||
virtual void AddProperty( CStrW PropertyName, CStrW Value ) = 0;
|
||||
|
||||
|
||||
inline IJSComplex() {}
|
||||
};
|
||||
|
||||
@ -117,6 +117,7 @@ public:
|
||||
m_Owner = Owner;
|
||||
m_PropertyRoot = PropertyRoot;
|
||||
}
|
||||
|
||||
static JSObject* CreateAccessor( JSContext* cx, T* Owner, CStrW PropertyRoot )
|
||||
{
|
||||
JSObject* Accessor = JS_NewObject( cx, &JSI_Class, NULL, NULL );
|
||||
@ -124,6 +125,7 @@ public:
|
||||
|
||||
return( Accessor );
|
||||
}
|
||||
|
||||
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
||||
{
|
||||
CJSComplexPropertyAccessor* Instance = (CJSComplexPropertyAccessor*)JS_GetPrivate( cx, obj );
|
||||
@ -135,6 +137,7 @@ public:
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
||||
{
|
||||
CJSComplexPropertyAccessor* Instance = (CJSComplexPropertyAccessor*)JS_GetPrivate( cx, obj );
|
||||
@ -146,6 +149,7 @@ public:
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
static JSBool JSEnumerate( JSContext* cx, JSObject* obj, JSIterateOp enum_op, jsval* statep, jsid *idp )
|
||||
{
|
||||
IJSComplex::IteratorState* it;
|
||||
@ -204,6 +208,7 @@ public:
|
||||
}
|
||||
return( JS_FALSE );
|
||||
}
|
||||
|
||||
static JSBool JSPrimitive( JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
|
||||
{
|
||||
CJSComplexPropertyAccessor* Instance = (CJSComplexPropertyAccessor*)JS_GetPrivate( cx, obj );
|
||||
@ -227,6 +232,7 @@ public:
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
static JSBool JSToString( JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
|
||||
{
|
||||
CJSComplexPropertyAccessor* Instance = (CJSComplexPropertyAccessor*)JS_GetPrivate( cx, obj );
|
||||
@ -253,7 +259,9 @@ public:
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
static JSClass JSI_Class;
|
||||
|
||||
static void ScriptingInit()
|
||||
{
|
||||
JSFunctionSpec JSI_methods[] = { { "valueOf", JSPrimitive, 0, 0, 0 }, { "toString", JSToString, 0, 0, 0 }, { 0 } };
|
||||
@ -698,12 +706,15 @@ public:
|
||||
JSI_methods[MethodID] = m_Methods[MethodID];
|
||||
|
||||
JSFunctionSpec watchAll = { "watchAll", SetWatchAll, 1, 0, 0 };
|
||||
JSI_methods[MethodID] = watchAll;
|
||||
JSI_methods[MethodID + 0] = watchAll;
|
||||
|
||||
JSFunctionSpec unwatchAll = { "unwatchAll", UnWatchAll, 1, 0, 0 };
|
||||
JSI_methods[MethodID + 1] = unwatchAll;
|
||||
|
||||
JSI_methods[MethodID + 2].name = 0;
|
||||
|
||||
JSI_class.name = ClassName;
|
||||
|
||||
g_ScriptingHost.DefineCustomObjectType( &JSI_class, Constructor, ConstructorMinArgs, JSI_props, JSI_methods, NULL, NULL );
|
||||
|
||||
delete[]( JSI_methods );
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "BaseEntity.h"
|
||||
#include "BaseEntityCollection.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "CStr.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
|
||||
@ -11,12 +13,14 @@
|
||||
|
||||
STL_HASH_SET<CStr, CStr_hash_compare> CBaseEntity::scriptsLoaded;
|
||||
|
||||
CBaseEntity::CBaseEntity()
|
||||
CBaseEntity::CBaseEntity( CPlayer* player )
|
||||
{
|
||||
m_player = player;
|
||||
m_base = NULL;
|
||||
|
||||
AddProperty( L"tag", &m_Tag, false );
|
||||
AddProperty( L"parent", &m_base, false );
|
||||
AddProperty( L"unmodified", &m_unmodified, false );
|
||||
AddProperty( L"actions.move.speed_curr", &m_speed );
|
||||
AddProperty( L"actions.move.turningradius", &m_turningRadius );
|
||||
AddProperty( L"actions.move.run.speed", &m_runSpeed );
|
||||
@ -348,6 +352,16 @@ bool CBaseEntity::loadXML( CStr filename )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( m_player == 0 )
|
||||
{
|
||||
m_unmodified = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_unmodified = g_EntityTemplateCollection.getTemplate( m_Tag, 0 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -432,7 +446,10 @@ JSObject* CBaseEntity::GetScriptExecContext( IEventTarget* target )
|
||||
jsval CBaseEntity::ToString( JSContext* cx, uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
{
|
||||
wchar_t buffer[256];
|
||||
swprintf( buffer, 256, L"[object EntityTemplate: %ls]", m_Tag.c_str() );
|
||||
if( m_player == 0 )
|
||||
swprintf( buffer, 256, L"[object EntityTemplate: %ls base]", m_Tag.c_str() );
|
||||
else
|
||||
swprintf( buffer, 256, L"[object EntityTemplate: %ls for player %d]", m_Tag.c_str(), m_player->GetPlayerID() );
|
||||
buffer[255] = 0;
|
||||
utf16string str16(buffer, buffer+wcslen(buffer));
|
||||
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, str16.c_str() ) ) );
|
||||
|
@ -27,10 +27,15 @@
|
||||
#include "ScriptObject.h"
|
||||
#include "XML/Xeromyces.h"
|
||||
|
||||
class CPlayer;
|
||||
|
||||
class CBaseEntity : public CJSComplex<CBaseEntity>, public IEventTarget
|
||||
{
|
||||
public:
|
||||
CBaseEntity();
|
||||
CPlayer* m_player; // Which player this template is for, or null for the no-player template
|
||||
// used to read unmodified values for upgrades and such.
|
||||
|
||||
CBaseEntity( CPlayer* player );
|
||||
~CBaseEntity();
|
||||
// Load from XML
|
||||
bool loadXML( CStr filename );
|
||||
@ -38,11 +43,13 @@ public:
|
||||
void XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& Source, CStrW BasePropertyName );
|
||||
|
||||
// Base stats
|
||||
|
||||
CBaseEntity* m_base;
|
||||
CStrW m_corpse;
|
||||
bool m_extant;
|
||||
|
||||
// The unmodified, no-player version of this template
|
||||
CBaseEntity* m_unmodified;
|
||||
|
||||
// The class types this entity has
|
||||
SClassSet m_classes;
|
||||
|
||||
|
@ -5,10 +5,10 @@
|
||||
#include "Model.h"
|
||||
#include "CLogger.h"
|
||||
#include "VFSUtil.h"
|
||||
#include "Player.h"
|
||||
|
||||
#define LOG_CATEGORY "entity"
|
||||
|
||||
|
||||
void CBaseEntityCollection::LoadFile( const char* path )
|
||||
{
|
||||
// Build the entity name -> filename mapping. This is done so that
|
||||
@ -35,11 +35,14 @@ int CBaseEntityCollection::loadTemplates()
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name )
|
||||
CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name, CPlayer* player )
|
||||
{
|
||||
// Find player ID
|
||||
int id = ( player == 0 ? NULL_PLAYER : player->GetPlayerID() );
|
||||
|
||||
// Check whether this template has already been loaded
|
||||
templateMap::iterator it = m_templates.find( name );
|
||||
if( it != m_templates.end() )
|
||||
templateMap::iterator it = m_templates[id].find( name );
|
||||
if( it != m_templates[id].end() )
|
||||
return( it->second );
|
||||
|
||||
// Find the filename corresponding to this template
|
||||
@ -50,7 +53,7 @@ CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name )
|
||||
CStr path( filename_it->second );
|
||||
|
||||
// Try to load to the entity
|
||||
CBaseEntity* newTemplate = new CBaseEntity();
|
||||
CBaseEntity* newTemplate = new CBaseEntity( player );
|
||||
if( !newTemplate->loadXML( path ) )
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s\"", path.c_str());
|
||||
@ -58,12 +61,12 @@ CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name )
|
||||
}
|
||||
|
||||
LOG(NORMAL, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s\"", path.c_str());
|
||||
m_templates[name] = newTemplate;
|
||||
m_templates[id][name] = newTemplate;
|
||||
|
||||
// Load the entity's parent, if it has one
|
||||
if( newTemplate->m_Base_Name.Length() )
|
||||
{
|
||||
CBaseEntity* base = getTemplate( newTemplate->m_Base_Name );
|
||||
CBaseEntity* base = getTemplate( newTemplate->m_Base_Name, player );
|
||||
if( base )
|
||||
{
|
||||
newTemplate->m_base = base;
|
||||
@ -89,6 +92,7 @@ void CBaseEntityCollection::getBaseEntityNames( std::vector<CStrW>& names )
|
||||
|
||||
CBaseEntityCollection::~CBaseEntityCollection()
|
||||
{
|
||||
for( templateMap::iterator it = m_templates.begin(); it != m_templates.end(); ++it )
|
||||
delete( it->second );
|
||||
for( int id = 0; id < PS_MAX_PLAYERS + 2; id++ )
|
||||
for( templateMap::iterator it = m_templates[id].begin(); it != m_templates[id].end(); ++it )
|
||||
delete( it->second );
|
||||
}
|
||||
|
@ -24,18 +24,23 @@
|
||||
#include "Singleton.h"
|
||||
#include "ObjectEntry.h"
|
||||
#include "BaseEntity.h"
|
||||
#include "Game.h"
|
||||
|
||||
#define g_EntityTemplateCollection CBaseEntityCollection::GetSingleton()
|
||||
#define NULL_PLAYER (PS_MAX_PLAYERS+1)
|
||||
|
||||
class CPlayer;
|
||||
|
||||
class CBaseEntityCollection : public Singleton<CBaseEntityCollection>
|
||||
{
|
||||
typedef std::map<CStrW, CBaseEntity*> templateMap;
|
||||
typedef std::map<CStrW, CStr> templateFilenameMap;
|
||||
templateMap m_templates;
|
||||
typedef STL_HASH_MAP<CStrW, CBaseEntity*, CStrW_hash_compare> templateMap;
|
||||
typedef STL_HASH_MAP<CStrW, CStr, CStrW_hash_compare> templateFilenameMap;
|
||||
|
||||
templateMap m_templates[PS_MAX_PLAYERS + 2];
|
||||
templateFilenameMap m_templateFilenames;
|
||||
public:
|
||||
~CBaseEntityCollection();
|
||||
CBaseEntity* getTemplate( CStrW entityType );
|
||||
CBaseEntity* getTemplate( CStrW entityType, CPlayer* player = 0 );
|
||||
int loadTemplates();
|
||||
void LoadFile( const char* path );
|
||||
|
||||
|
@ -39,6 +39,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
m_orientation.Y = orientation;
|
||||
m_ahead.x = sin( m_orientation.Y );
|
||||
m_ahead.y = cos( m_orientation.Y );
|
||||
m_player = 0;
|
||||
|
||||
// set sane default in case someone forgets to add this to the entity's
|
||||
// XML file, which is prone to happen. (prevents crash below when
|
||||
@ -235,6 +236,12 @@ void CEntity::loadBase()
|
||||
}
|
||||
|
||||
m_actor_transform_valid = false;
|
||||
|
||||
if( m_player )
|
||||
{
|
||||
// Make sure the actor has the right player colour
|
||||
m_actor->SetPlayerID( m_player->GetPlayerID() );
|
||||
}
|
||||
}
|
||||
|
||||
void CEntity::kill()
|
||||
@ -507,7 +514,7 @@ void CEntity::update( size_t timestep )
|
||||
m_orderQueue.pop_front();
|
||||
break;
|
||||
default:
|
||||
debug_warn("Invalid entity order" );
|
||||
debug_warn( "Invalid entity order" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,15 +91,9 @@ HEntity CEntityManager::create( CBaseEntity* base, CVector3D position, float ori
|
||||
return( HEntity( m_nextalloc++ ) );
|
||||
}
|
||||
|
||||
HEntity CEntityManager::create( const CStrW templateName, CVector3D position, float orientation, const std::set<CStrW>& actorSelections )
|
||||
HEntity CEntityManager::createFoundation( CStrW templateName, CPlayer* player, CVector3D position, float orientation )
|
||||
{
|
||||
CBaseEntity* templateObj = g_EntityTemplateCollection.getTemplate( templateName );
|
||||
return( create( templateObj, position, orientation, actorSelections ) );
|
||||
}
|
||||
|
||||
HEntity CEntityManager::createFoundation( CStrW templateName, CVector3D position, float orientation )
|
||||
{
|
||||
CBaseEntity* base = g_EntityTemplateCollection.getTemplate( templateName );
|
||||
CBaseEntity* base = g_EntityTemplateCollection.getTemplate( templateName, player );
|
||||
debug_assert( base );
|
||||
if( !base )
|
||||
return HEntity();
|
||||
|
@ -51,9 +51,8 @@ public:
|
||||
~CEntityManager();
|
||||
|
||||
HEntity create( CBaseEntity* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections );
|
||||
HEntity create( CStrW templateName, CVector3D position, float orientation, const std::set<CStrW>& actorSelections );
|
||||
|
||||
HEntity createFoundation( CStrW templateName, CVector3D position, float orientation );
|
||||
HEntity createFoundation( CStrW templateName, CPlayer* player, CVector3D position, float orientation );
|
||||
|
||||
HEntity* getByHandle( u16 index );
|
||||
CHandle *getHandle( int index );
|
||||
|
@ -32,25 +32,28 @@ void CPathfindEngine::requestLowLevelPath( HEntity entity, const CVector2D& dest
|
||||
if ( mLowPathfinder.findPath(source, destination, entity->m_player) )
|
||||
{
|
||||
std::vector<CVector2D> path = mLowPathfinder.getLastPath();
|
||||
std::vector<CVector2D>::iterator it;
|
||||
CEntityOrder node;
|
||||
for( it = path.begin(); (it+1) != path.end(); it++ )
|
||||
if( path.size() > 0 )
|
||||
{
|
||||
if ( !contact )
|
||||
std::vector<CVector2D>::iterator it;
|
||||
CEntityOrder node;
|
||||
for( it = path.begin(); (it+1) != path.end(); it++ )
|
||||
{
|
||||
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Is this right?
|
||||
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
|
||||
if ( !contact )
|
||||
{
|
||||
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Is this right?
|
||||
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
|
||||
}
|
||||
node.m_data[0].location = *it;
|
||||
entity->m_orderQueue.push_back(node);
|
||||
}
|
||||
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
|
||||
node.m_data[0].location = *it;
|
||||
entity->m_orderQueue.push_back(node);
|
||||
}
|
||||
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
|
||||
node.m_data[0].location = *it;
|
||||
entity->m_orderQueue.push_back(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -335,19 +335,17 @@ uint CSimulation::TranslateMessage(CNetMessage* pMsg, uint clientMask, void* UNU
|
||||
{
|
||||
CPlaceObject *msg = (CPlaceObject *) pMsg;
|
||||
|
||||
// Figure out the player
|
||||
CPlayer* player = 0;
|
||||
if(msg->m_Entities.size() > 0)
|
||||
player = msg->m_Entities[0]->GetPlayer();
|
||||
else
|
||||
player = g_Game->GetLocalPlayer();
|
||||
|
||||
// Create the object
|
||||
CVector3D pos(msg->m_X/1000.0f, msg->m_Y/1000.0f, msg->m_Z/1000.0f);
|
||||
HEntity newObj = g_EntityManager.createFoundation( msg->m_Template, pos, msg->m_Angle/1000.0f );
|
||||
|
||||
if(msg->m_Entities.size() > 0)
|
||||
{
|
||||
newObj->SetPlayer(msg->m_Entities[0]->GetPlayer());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Object might have been placed from the console just for testing
|
||||
newObj->SetPlayer(g_Game->GetLocalPlayer());
|
||||
}
|
||||
HEntity newObj = g_EntityManager.createFoundation( msg->m_Template, player, pos, msg->m_Angle/1000.0f );
|
||||
newObj->SetPlayer(player);
|
||||
|
||||
// Order all the selected units to work on the new object using the given action
|
||||
order.m_type = CEntityOrder::ORDER_START_CONSTRUCTION;
|
||||
|
Loading…
Reference in New Issue
Block a user