1
0
forked from 0ad/0ad

# 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:
Matei 2006-05-13 22:11:46 +00:00
parent 68644fb42b
commit 1e3f5f5d3e
12 changed files with 110 additions and 57 deletions

View File

@ -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

View File

@ -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() );

View File

@ -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 );

View File

@ -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() ) ) );

View File

@ -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;

View File

@ -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 );
}

View File

@ -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 );

View File

@ -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" );
}
}

View File

@ -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();

View File

@ -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 );

View File

@ -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
{

View File

@ -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;