1
1
forked from 0ad/0ad

#Configurable game speed, techs, elevation attack bonus

-techs are not operational yet
-set the game speed with setSimRate() in the console or in the config
file under hotkey.speed.increase or hotkey.speed.decrease
-made a few other small fixes

This was SVN commit r3950.
This commit is contained in:
pyrolink 2006-06-06 06:31:17 +00:00
parent 19c31d97ff
commit e4c40841b2
17 changed files with 841 additions and 20 deletions

View File

@ -52,10 +52,17 @@
<Height>-1.0</Height>
<Name></Name>
</Rank>
<Flank_Penalty>
<Sectors>6</Sectors>
<Value>.2</Value>
</Flank_Penalty>
<Elevation>
<Rate>1.0</Rate>
<Value>0.0</Value>
</Elevation>
<Pitch>
<Sectors>7</Sectors>
<Value>.1</Value>

View File

@ -377,7 +377,7 @@ function performAttack( evt )
dmg.pierce = parseInt(a.damage * a.pierce);
}
// Add flank bonus
// Add flank penalty
if(evt.target.traits.flank_penalty)
{
var flank = (evt.target.getAttackDirections()-1)*evt.target.traits.flank_penalty.value;
@ -403,7 +403,13 @@ function performAttackRanged( evt )
dmg.hack = parseInt(a.damage * a.hack);
dmg.pierce = parseInt(a.damage * a.pierce);
// Add flank bonus
// Add flank penalty and elevation bonus
var elevationBonus = (this.getHeight() - evt.target.getHeight())/this.traits.elevation.rate * this.traits.elevation.value;
dmg.crush += dmg.crush * elevationBonus;
dmg.hack += dmg.hack * elevationBonus;
dmg.pierce += dmg.pierce * elevationBonus;
console.write( dmg.crush + "|" + dmg.hack );
if(evt.target.traits.flank_penalty)
{
var flank = (evt.target.getAttackDirections()-1)*evt.target.traits.flank_penalty.value;

View File

@ -54,13 +54,13 @@ CSprite::~CSprite()
void CSprite::Render()
{
BeginBillboard();
glDisable(GL_CULL_FACE);
glPushMatrix();
glTranslatef(m_translation.X, m_translation.Y, m_translation.Z);
glScalef(m_scale.X, m_scale.Y, m_scale.Z);
BeginBillboard();
glDisable(GL_CULL_FACE);
if ( m_texture->GetHandle() != 0 )
ogl_tex_bind(m_texture->GetHandle());
glColor4fv(m_colour);
@ -187,7 +187,7 @@ void CSprite::SetColour(float * colour)
m_colour[3] = colour[3];
}
// should be called before any other gl calls
//Must call glPushMatrix() before this. Should be called before any other gl calls
void CSprite::BeginBillboard()
{
float newMatrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f,
@ -207,7 +207,6 @@ void CSprite::BeginBillboard()
newMatrix[9] = currentMatrix[6];
newMatrix[10] = currentMatrix[10];
glPushMatrix();
glMultMatrixf(newMatrix);
}

View File

@ -38,7 +38,8 @@ CGame::CGame():
m_pLocalPlayer(NULL),
m_GameStarted(false),
m_Paused(false),
m_Time(0)
m_Time(0),
m_SimRate(1.0f)
{
debug_printf("CGame::CGame(): Game object CREATED; initializing..\n");
}
@ -139,7 +140,7 @@ void CGame::Update(double deltaTime)
{
return;
}
deltaTime *= m_SimRate;
m_Time += deltaTime;
m_Simulation->Update(deltaTime);

View File

@ -2,7 +2,7 @@
#define _ps_Game_H
#include "ps/Errors.h"
#include "maths/MathUtil.h"
#include <vector>
class CWorld;
@ -29,6 +29,7 @@ class CGame
bool m_GameStarted;
float m_Time;
float m_SimRate;
enum EOG
{
@ -92,6 +93,11 @@ public:
inline float GetTime()
{ return m_Time; }
inline void SetSimRate(float simRate)
{ m_SimRate=clamp(simRate, 0.0f, simRate); }
inline float GetSimRate()
{ return m_SimRate; }
private:
PSRETURN RegisterInit(CGameAttributes* pAttribs);

View File

@ -345,8 +345,9 @@ void Render()
PROFILE_START( "render health bars" );
pglActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE2_ARB);
glDisable(GL_TEXTURE_2D);
//Not all hardware supports 3 texture units!
//pglActiveTextureARB(GL_TEXTURE2_ARB);
//glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE0_ARB);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();

View File

@ -140,7 +140,9 @@ static SHotkeyInfo hotkeyInfo[] =
{ HOTKEY_WATER_TOGGLE, "water.toggle", SDLK_q, 0 },
{ HOTKEY_WATER_RAISE, "water.toggle", SDLK_a, 0 },
{ HOTKEY_WATER_LOWER, "water.toggle", SDLK_z, 0 },
{ HOTKEY_PAUSE, "pause", SDLK_PAUSE, 0 }
{ HOTKEY_PAUSE, "pause", SDLK_PAUSE, 0 },
{ HOTKEY_SPEED_INCREASE, "speed.increase", 0, 0 },
{ HOTKEY_SPEED_DECREASE, "speed.decrease", 0, 0 }
};
/* SDL-type ends */

View File

@ -104,6 +104,8 @@ enum
HOTKEY_WATER_RAISE,
HOTKEY_WATER_LOWER,
HOTKEY_PAUSE,
HOTKEY_SPEED_INCREASE,
HOTKEY_SPEED_DECREASE,
HOTKEY_LAST,

View File

@ -9,7 +9,6 @@
#include "ScriptGlue.h"
#include "JSConversions.h"
#include "GameEvents.h"
#include "graphics/GameView.h"
#include "graphics/LightEnv.h"
#include "graphics/MapWriter.h"
@ -35,6 +34,7 @@
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation/BaseEntityCollection.h"
#include "simulation/BaseTechCollection.h"
#include "simulation/Entity.h"
#include "simulation/EntityFormation.h"
#include "simulation/EntityHandles.h"
@ -267,9 +267,13 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
CreateFormationMessage(messages, msg, entities[i]);
formation->SetDuplication(true);
entities.erase( entities.begin()+i ); //we don't want to be in two orders
--i;
}
else if ( duplicate )
{
entities.erase( entities.begin()+i );
--i;
}
}
}
@ -324,6 +328,37 @@ JSBool isFormationLocked( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval
*rval = entity->GetFormation()->IsLocked() ? JS_TRUE : JS_FALSE;
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// Techs
//-----------------------------------------------------------------------------
JSBool getTechTemplate( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
{
REQUIRE_MIN_PARAMS(2, getTechTemplate);
CStrW name = ToPrimitive<CStrW>( argv[0] );
PS_uint playerID = (PS_uint)ToPrimitive<int>( argv[1] );
rval = JSVAL_NULL;
if ( g_Game->GetPlayer(playerID) )
{
//The tech will now temporarily belong to this player. This will change on the next call.
CBaseTech* tech = g_BaseTechCollection.getTemplate(name);
if ( tech )
{
tech->setPlayer( g_Game->GetPlayer(playerID) );
*rval = OBJECT_TO_JSVAL(tech->GetScript());
}
else
JS_ReportError(cx, "Invalid tech template name \"%s\" passed for getTechTemplate()", name.c_str() );
}
else
JS_ReportError(cx, "Invalid playerID \"%d\"passed for getTechTemplate()", playerID);
if ( rval )
return JS_TRUE;
return JS_FALSE;
}
//-----------------------------------------------------------------------------
// Events
@ -523,6 +558,16 @@ JSBool cancelTimer( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNU
return( JS_TRUE );
}
//Set the simulation rate scalar-time becomes time * SimRate.
//Params: rate [float] : sets SimRate
JSBool setSimRate(JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNUSED(rval))
{
REQUIRE_MIN_PARAMS(1, setSimRate);
REQUIRE_MAX_PARAMS(1, setSimRate);
g_Game->SetSimRate( ToPrimitive<float>(argv[0]) );
return JS_TRUE;
}
//-----------------------------------------------------------------------------
@ -1155,6 +1200,8 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC(lockEntityFormation, lockEntityFormation, 1)
JS_FUNC(isFormationLocked, isFormationLocked, 1)
//Tech
JS_FUNC(getTechTemplate, getTechTemplate, 2)
// Camera
JS_FUNC(setCameraTarget, setCameraTarget, 1)
@ -1186,6 +1233,7 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC(setInterval, setInterval, 2)
JS_FUNC(cancelInterval, cancelInterval, 0)
JS_FUNC(cancelTimer, cancelTimer, 0)
JS_FUNC(setSimRate, setSimRate, 1)
// Game Setup
JS_FUNC(startGame, startGame, 0)

View File

@ -57,6 +57,7 @@ CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name, CPlayer* player )
if( !newTemplate->loadXML( path ) )
{
LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s\"", path.c_str());
delete newTemplate;
return( NULL );
}

View File

@ -54,6 +54,7 @@ CBaseFormation* CBaseFormationCollection::getTemplate( CStrW name )
if( !newTemplate->loadXML( path ) )
{
LOG(ERROR, LOG_CATEGORY, "CBaseFormationCollection::loadTemplates(): Couldn't load template \"%s\"", path.c_str());
delete newTemplate;
return( NULL );
}

View File

@ -0,0 +1,493 @@
#include "precompiled.h"
#include "BaseTech.h"
#include "BaseTechCollection.h"
#include "EntityManager.h"
#include "ps/CStr.h"
#include "ps/CLogger.h"
#include "scripting/ScriptingHost.h"
#include "ps/XML/Xeromyces.h"
#include "ps/XML/XeroXMB.h"
#define LOG_CATEGORY "Techs"
STL_HASH_SET<CStr, CStr_hash_compare> CBaseTech::m_scriptsLoaded;
CBaseTech::CBaseTech()
{
m_researched = m_excluded=false;
AddProperty(L"generic", &CBaseTech::m_Generic, true);
AddProperty(L"specific", &CBaseTech::m_Specific, true);
AddProperty(L"icon", &CBaseTech::m_Icon); //GUI might want to change this...?
AddProperty<int>(L"icon_cell", &CBaseTech::m_IconCell);
AddProperty(L"classes", &CBaseTech::m_Classes, true);
AddProperty(L"history", &CBaseTech::m_History, true);
AddProperty<float>(L"time", &CBaseTech::m_ReqTime); //Techs may upgrade research time and cost of other techs
AddProperty<float>(L"food", &CBaseTech::m_ReqFood);
AddProperty<float>(L"wood", &CBaseTech::m_ReqWood);
AddProperty<float>(L"stone", &CBaseTech::m_ReqStone);
AddProperty<float>(L"ore", &CBaseTech::m_ReqOre);
m_effectFunction = NULL;
m_JSFirst = false;
ONCE( ScriptingInit() );
}
bool CBaseTech::loadXML( CStr filename )
{
CXeromyces XeroFile;
if (XeroFile.Load(filename) != PSRETURN_OK)
return false;
#define EL(x) int el_##x = XeroFile.getElementID(#x)
EL(tech);
EL(id);
EL(req);
EL(effect);
#undef EL
XMBElement Root = XeroFile.getRoot();
if ( Root.getNodeName() != el_tech )
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech: XML root was not \"Tech\" in file %s. Load failed.", filename.c_str() );
return false;
}
XMBElementList RootChildren = Root.getChildNodes();
bool ret;
for ( int i=0; i<RootChildren.Count; ++i )
{
XMBElement element = RootChildren.item(i);
int name = element.getNodeName();
if ( name == el_id )
ret = loadELID( element, XeroFile );
else if ( name == el_req )
ret = loadELReq( element, XeroFile );
else if ( name == el_effect )
ret = loadELEffect( element, XeroFile, filename );
else
continue;
if ( !ret )
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech: Load failed for file %s", filename.c_str() );
return false;
}
}
return true;
}
bool CBaseTech::loadELID( XMBElement ID, CXeromyces& XeroFile )
{
#define EL(x) int el_##x = XeroFile.getElementID(#x)
EL(generic);
EL(specific);
EL(icon);
EL(icon_cell);
EL(classes);
EL(rollover);
EL(history);
#undef EL
XMBElementList children = ID.getChildNodes();
for ( int i=0; i<children.Count; ++i )
{
XMBElement element = children.item(i);
int name = element.getNodeName();
CStr value = CStr(element.getText());
if ( name == el_generic )
m_Generic = value;
else if ( name == el_specific )
m_Specific = value;
else if ( name == el_icon )
m_Icon = value;
else if ( name == el_icon_cell )
m_IconCell = value.ToInt();
else if ( name == el_classes )
m_Classes = value;
else if ( name == el_rollover )
continue;
else if ( name == el_history )
m_History = value;
else
{
const char* tagName = XeroFile.getElementString(name).c_str();
LOG( ERROR, LOG_CATEGORY, "CBaseTech: invalid tag %s for XML file", tagName );
return false;
}
}
return true;
}
bool CBaseTech::loadELReq( XMBElement Req, CXeromyces& XeroFile )
{
#define EL(x) int el_##x = XeroFile.getElementID(#x)
EL(time);
EL(resource);
EL(food);
EL(tech);
EL(stone);
EL(ore);
EL(wood);
EL(entity);
#undef EL
XMBElementList children = Req.getChildNodes();
for ( int i=0; i<children.Count; ++i )
{
XMBElement element = children.item(i);
int name = element.getNodeName();
CStr value = element.getText();
if ( name == el_time )
m_ReqTime = value.ToFloat();
else if ( name == el_resource )
{
XMBElementList resChildren = element.getChildNodes();
for ( int j=0; j<resChildren.Count; ++j )
{
XMBElement resElement = resChildren.item(j);
int resName = resElement.getNodeName();
CStr resValue = CStr(resElement.getText());
if ( resName == el_food ) //NOT LOADED-GET CHILD NODES
m_ReqFood = resValue.ToFloat();
else if ( resName == el_wood )
m_ReqWood = resValue.ToFloat();
else if ( resName == el_stone )
m_ReqStone = resValue.ToFloat();
else if ( resName == el_ore )
m_ReqOre = resValue.ToFloat();
else
{
const char* tagName = XeroFile.getElementString(name).c_str();
LOG( ERROR, LOG_CATEGORY, "CBaseTech: invalid tag %s for XML file", tagName );
return false;
}
}
}
else if ( name == el_entity )
m_ReqEntities.push_back( value );
else if ( name == el_tech )
m_ReqTechs.push_back( value );
else
{
const char* tagName = XeroFile.getElementString(name).c_str();
LOG( ERROR, LOG_CATEGORY, "CBaseTech: invalid tag %s for XML file", tagName );
return false;
}
}
return true;
}
bool CBaseTech::loadELEffect( XMBElement effect, CXeromyces& XeroFile, CStr& filename )
{
#define EL(x) int el_##x = XeroFile.getElementID(#x)
#define AT(x) int at_##x = XeroFile.getAttributeID(#x)
EL(target);
EL(pair);
EL(modifier);
EL(attribute);
EL(value);
EL(set);
EL(script);
EL(function);
AT(name);
AT(order);
AT(file);
#undef EL
#undef AT
XMBElementList children = effect.getChildNodes();
for ( int i=0; i<children.Count; ++i )
{
XMBElement element = children.item(i);
int name = element.getNodeName();
CStr value = element.getText();
if ( name == el_target )
m_Targets.push_back(value);
else if ( name == el_pair )
m_Pairs.push_back(value);
else if ( name == el_modifier )
{
XMBElementList modChildren = element.getChildNodes();
m_Modifiers.push_back(Modifier());
for ( int j=0; j<modChildren.Count; ++j )
{
XMBElement modElement = modChildren.item(j);
CStr modValue = CStr(modElement.getText());
if ( modElement.getNodeName() == el_attribute)
{
if ( CEntity::m_AttributeTable.find( modValue ) == CEntity::m_AttributeTable.end() )
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech::loadXML invalid attribute %s for modifier attribute", modValue);
m_Modifiers.pop_back();
return false;
}
else
m_Modifiers.back().attribute = modValue;
}
else if ( modElement.getNodeName() == el_value )
m_Modifiers.back().value = modValue.ToFloat();
else
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech::loadXML invalid tag inside \"Modifier\" tag" );
m_Modifiers.pop_back();
return false;
}
}
}
else if ( name == el_set )
{
XMBElementList setChildren = element.getChildNodes();
m_Sets.push_back(Modifier());
for ( int j=0; j<setChildren.Count; ++j )
{
XMBElement setElement = setChildren.item(j);
CStr setValue = CStr(setElement.getText());
if ( setElement.getNodeName() == el_attribute)
{
if ( CEntity::m_AttributeTable.find( setValue ) == CEntity::m_AttributeTable.end() )
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech::loadXML invalid attribute %s for \"set\" attribute", setValue);
m_Sets.pop_back();
return false;
}
else
m_Sets.back().attribute = setValue;
}
else if ( setElement.getNodeName() == el_value )
m_Sets.back().value = setValue.ToFloat();
else
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech::loadXML invalid tag inside \"Set\" tag" );
m_Sets.pop_back();
return false;
}
}
}
else if ( name == el_script )
{
CStr Include = element.getAttributes().getNamedItem( at_file );
if( Include.Length() && m_scriptsLoaded.find( Include ) == m_scriptsLoaded.end() )
{
m_scriptsLoaded.insert( Include );
g_ScriptingHost.RunScript( Include );
}
CStr Inline = element.getText();
if( Inline.Length() )
{
g_ScriptingHost.RunMemScript( Inline.c_str(), Inline.Length(), filename, element.getLineNumber() );
}
}
else if ( name == el_function )
{
utf16string funcName = element.getAttributes().getNamedItem( at_name );
CStr Inline = element.getText();
//default to first
m_JSFirst = (utf16string() == element.getAttributes().getNamedItem( at_order ));
if ( funcName != utf16string() )
{
jsval fnval;
JSBool ret = JS_GetUCProperty( g_ScriptingHost.GetContext(), g_ScriptingHost.GetGlobalObject(), funcName.c_str(), funcName.size(), &fnval );
debug_assert( ret );
JSFunction* fn = JS_ValueToFunction( g_ScriptingHost.GetContext(), fnval );
if( !fn )
{
LOG( ERROR, LOG_CATEGORY, "CBaseTech::LoadXML: Function does not exist for %hs in file %s. Load failed.", funcName.c_str(), filename.c_str() );
return false;
}
m_effectFunction->SetFunction( fn );
}
else if ( Inline != CStr() )
m_effectFunction->Compile( CStrW( filename ) + L"::" + (CStrW)funcName + L" (" + CStrW( element.getLineNumber() ) + L")", Inline );
//(No error needed; scripts are optional)
}
else
{
const char* tagName = XeroFile.getElementString(name).c_str();
LOG( ERROR, LOG_CATEGORY, "CBaseTech: invalid tag %s for XML file", tagName );
return false;
}
}
return true;
}
bool CBaseTech::isTechValid()
{
if ( m_excluded )
return false;
if ( hasReqEntities() && hasReqTechs() )
return true;
return false;
}
bool CBaseTech::hasReqEntities()
{
bool ret=true;
std::vector<HEntity>* entities = m_player->GetControlledEntities();
for ( std::vector<CStr>::iterator it=m_ReqEntities.begin(); it != m_ReqEntities.end(); it++ )
{
for( CEntityList::iterator it2=entities->begin(); it2 != entities->end(); it2++ )
{
if ( (*it2)->m_classes.IsMember(*it) )
{
ret=true;
break;
}
}
}
delete entities;
return ret;
}
bool CBaseTech::hasReqTechs()
{
bool ret=false;
for ( std::vector<CStr>::iterator it=m_ReqTechs.begin(); it != m_ReqTechs.end(); it++ )
{
if ( g_BaseTechCollection.getTemplate( (CStrW)*it )->isResearched() )
{
ret=true;
break;
}
}
return ret;
}
//JS stuff
void CBaseTech::ScriptingInit()
{
AddMethod<jsval, &CBaseTech::ApplyEffects>( "applyEffects", 1 );
AddMethod<jsval, &CBaseTech::IsExcluded>( "isExcluded", 0 );
AddMethod<jsval, &CBaseTech::IsValid>( "isValid", 0 );
AddMethod<jsval, &CBaseTech::IsResearched>( "isResearched", 0 );
AddMethod<jsval, &CBaseTech::GetPlayerID>( "getPlayerID", 0 );
AddMethod<jsval, &CBaseTech::IsJSFirst>( "isJSFirst", 0 );
CJSObject<CBaseTech>::ScriptingInit("TechTemplate");
}
jsval CBaseTech::ApplyEffects( JSContext* cx, uintN argc, jsval* argv )
{
if ( !isTechValid() )
return JS_FALSE;
else if ( argc < 2 )
{
JS_ReportError(cx, "too few parameters for CBaseTech::ApplyEffects.");
return JS_FALSE;
}
//Order overriding for some special case
bool first = ToPrimitive<bool>( argv[0] );
bool invert = ToPrimitive<bool>( argv[1] );
//Optional type overriding if some in some special case the script wants to modify non-floats
CStr varType("float");
if ( argc == 3 )
varType = ToPrimitive<CStr>( argv[2] );
if ( first )
m_effectFunction->Run( this->GetScript() );
//Disable other templates
for ( std::vector<CStr>::iterator it=m_Pairs.begin(); it != m_Pairs.end(); it++ )
g_BaseTechCollection.getTemplate(*it)->setExclusion(true);
std::vector<HEntity>* entities = m_player->GetControlledEntities();
if ( entities->empty() )
{
delete entities;
return JS_FALSE;
}
//Find which entities should be affected
for ( std::vector<CStr>::iterator it = m_Targets.begin(); it != m_Targets.end(); it++ )
{
for ( size_t i=0; i<entities->size(); ++i )
{
if ( !(*entities)[i]->m_classes.IsMember( *it ) )
entities->erase(entities->begin() + i);
}
}
CEntityList::iterator HEit = entities->begin();
for ( ; HEit != entities->end(); HEit++ )
{
for ( std::vector<Modifier>::iterator mod=m_Modifiers.begin(); mod!=m_Modifiers.end(); mod++ )
{
//Get the member corresponding to the javascript attribute string
void* attribute = (char*)&**HEit + (*HEit)->m_AttributeTable[mod->attribute];
float modValue = (invert ? -mod->value : mod->value);
if ( varType == "int" )
*(int*)attribute += (int)modValue;
if ( varType == "double" )
*(double*)attribute += (double)modValue;
else
*(float*)attribute += (float)modValue;
}
}
for ( HEit = entities->begin(); HEit != entities->end(); HEit++ )
{
for ( std::vector<Modifier>::iterator set=m_Sets.begin(); set!=m_Sets.end(); set++ )
{
//Get the member corresponding to the javascript attribute string
void* attribute = (char*)&**HEit + (*HEit)->m_AttributeTable[set->attribute];
float setValue = invert ? -set->value : set->value;
if ( varType == "int" )
*(int*)attribute += (int)setValue;
if ( varType == "double" )
*(double*)attribute += (double)setValue;
else
*(float*)attribute += (float)setValue;
}
}
if ( !first )
m_effectFunction->Run( this->GetScript() );
delete entities;
return JS_TRUE;
}
jsval CBaseTech::IsValid( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
if ( isTechValid() )
return JS_TRUE;
return JS_FALSE;
}
jsval CBaseTech::IsExcluded( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
if ( m_excluded )
return JS_TRUE;
return JS_FALSE;
}
jsval CBaseTech::IsResearched( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
if ( isResearched() )
return JS_TRUE;
return JS_FALSE;
}
inline jsval CBaseTech::GetPlayerID( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal( m_player->GetPlayerID() );
}
jsval CBaseTech::IsJSFirst( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
if ( m_JSFirst )
return JS_TRUE;
return JS_FALSE;
}

View File

@ -0,0 +1,85 @@
//Andrew aka pyrolink
//ajdecker1022@msn.com
//Holds template information for technologies and research
#ifndef BASETECH_INCLUDED
#define BASETECH_INCLUDED
#include <vector>
#include "scripting/ScriptableComplex.h"
class CStr;
class XMBElement;
class CXeromyces;
class CBaseTech : public CJSObject<CBaseTech>
{
friend class CBaseTechCollection;
typedef struct Modifier
{
CStr attribute;
float value;
Modifier() { value = 0; }
};
static STL_HASH_SET<CStr, CStr_hash_compare> m_scriptsLoaded;
public:
CBaseTech();
~CBaseTech() {}
//JS functions
static void ScriptingInit();
jsval ApplyEffects( JSContext* cx, uintN argc, jsval* argv );
jsval IsValid( JSContext* cx, uintN argc, jsval* argv );
jsval IsResearched( JSContext* cx, uintN argc, jsval* argv );
jsval IsJSFirst( JSContext* cx, uintN argc, jsval* argv );
jsval IsExcluded( JSContext* cx, uintN argc, jsval* argv );
inline jsval GetPlayerID( JSContext* cx, uintN argc, jsval* argv );
bool isTechValid();
inline bool isResearched() { return m_researched; }
void setPlayer( CPlayer* player ) { m_player=player; }
void setExclusion( bool exclude ) { m_excluded=exclude; }
bool loadXML( CStr filename );
bool loadELID( XMBElement ID, CXeromyces& XeroFile );
bool loadELReq( XMBElement Req, CXeromyces& XeroFile );
bool loadELEffect( XMBElement Effect, CXeromyces& XeroFile, CStr& filename );
private:
CStr m_Generic;
CStr m_Specific;
CStr m_Icon;
int m_IconCell;
CStr m_Classes;
CStr m_History;
float m_ReqTime;
float m_ReqWood;
float m_ReqFood;
float m_ReqStone;
float m_ReqOre;
std::vector<CStr> m_ReqEntities;
std::vector<CStr> m_ReqTechs;
std::vector<CStr> m_Pairs;
std::vector<CStr> m_Targets;
std::vector<Modifier> m_Modifiers;
std::vector<Modifier> m_Sets;
CPlayer* m_player; //Which player this tech belongs to
CScriptObject* m_effectFunction;
bool m_JSFirst; //Should JS effect function run before C++
bool m_excluded;
bool m_researched;
bool hasReqEntities();
bool hasReqTechs();
};
#endif

View File

@ -0,0 +1,71 @@
#include "precompiled.h"
#include "BaseTechCollection.h"
#include "ps/CLogger.h"
#include "ps/VFSUtil.h"
#define LOG_CATEGORY "tech"
void CBaseTechCollection::LoadFile( const char* path )
{
//Make tech file reading
CStrW tag = CStr(path).AfterLast("/").BeforeLast(".xml");
m_templateFilenames[tag] = path;
}
static void LoadTechThunk( const char* path, const DirEnt* UNUSED(ent), void* context )
{
CBaseTechCollection* this_ = (CBaseTechCollection*)context;
this_->LoadFile(path);
}
int CBaseTechCollection::loadTemplates()
{
// Load all files in techs/ and subdirectories.
THROW_ERR( vfs_dir_enum( "techs/", VFS_DIR_RECURSIVE, "*.xml",
LoadTechThunk, this ) );
return 0;
}
CBaseTech* CBaseTechCollection::getTemplate( CStrW name )
{
// Check whether this template has already been loaded.
//If previously loaded, all slots will be found, so any entry works.
templateMap::iterator it = m_templates.find( name );
if( it != m_templates.end() )
return( it->second );
// Find the filename corresponding to this template
templateFilenameMap::iterator filename_it = m_templateFilenames.find( name );
if( filename_it == m_templateFilenames.end() )
return( NULL );
CStr path( filename_it->second );
//Try to load to the tech
CBaseTech* newTemplate = new CBaseTech();
if( !newTemplate->loadXML( path ) )
{
LOG(ERROR, LOG_CATEGORY, "CBaseTechCollection::loadTemplates(): Couldn't load template \"%s\"", path.c_str());
delete newTemplate;
return( NULL );
}
m_templates[name] = newTemplate;
LOG(NORMAL, LOG_CATEGORY, "CBaseTechCollection::loadTemplates(): Loaded template \"%s\"", path.c_str());
return newTemplate;
}
void CBaseTechCollection::getBaseTechNames( std::vector<CStrW>& names )
{
for( templateFilenameMap::iterator it = m_templateFilenames.begin(); it != m_templateFilenames.end(); ++it )
if( ! (it->first.Length() > 8 && it->first.Left(8) == L"template"))
names.push_back( it->first );
}
CBaseTechCollection::~CBaseTechCollection()
{
for( templateMap::iterator it = m_templates.begin(); it != m_templates.end(); ++it )
delete( it->second );
}

View File

@ -0,0 +1,34 @@
//Andrew aka pyrolink - ajdecker1022@msn.com
//Manages the tech templates. More detail: see CBaseFormation and CBaseEntity (collections)
#ifndef BASETECH_COLLECTION_INCLUDED
#define BASETECH_COLLECTION_INCLUDED
#include <vector>
#include "ps/CStr.h"
#include "ps/Singleton.h"
#include "BaseTech.h"
#include "ps/Game.h"
#define g_BaseTechCollection CBaseTechCollection::GetSingleton()
class CBaseTechCollection : public Singleton<CBaseTechCollection>
{
typedef std::map<CStrW, CBaseTech*> templateMap;
typedef std::map<CStrW, CStr> templateFilenameMap;
templateMap m_templates;
templateFilenameMap m_templateFilenames;
public:
~CBaseTechCollection();
CBaseTech* getTemplate( CStrW techType );
int loadTemplates();
void LoadFile( const char* path );
// Create a list of the names of all base techs, excluding template_*,
// for display in ScEd's entity-selection box.
void getBaseTechNames( std::vector<CStrW>& names );
};
#endif

View File

@ -32,6 +32,7 @@ extern int g_xres, g_yres;
#include <algorithm>
using namespace std;
std::map<CStr, size_t> CEntity::m_AttributeTable;
CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, CStrW building )
{
@ -233,6 +234,61 @@ void CEntity::loadBase()
}
}
void CEntity::initAttributes(const CEntity* _this)
{
#define getoffset(member) \
(size_t) ((unsigned char*)&_this->member - (unsigned char*)_this)
#define getoffset_action(member, mem2) \
(size_t) ((unsigned char*)&_this->member.mem2 - (unsigned char*)_this)
//Add the attribute name and the variable that holds it
CEntity::m_AttributeTable["actions.move.speed_curr"] = getoffset(m_speed);
CEntity::m_AttributeTable["actions.move.run.speed"] = getoffset(m_runSpeed);
CEntity::m_AttributeTable["actions.move.run.rangemin"] = getoffset_action(m_run, m_MinRange);
CEntity::m_AttributeTable["actions.move.run.range"] = getoffset_action(m_run, m_MaxRange);
CEntity::m_AttributeTable["actions.move.run.regen_rate"] = getoffset(m_runRegenRate);
CEntity::m_AttributeTable["actions.move.run.decay_rate"] = getoffset(m_runDecayRate);
CEntity::m_AttributeTable["actions.move.pass_through_allies"] = getoffset(m_passThroughAllies);
CEntity::m_AttributeTable["traits.extant"] = getoffset(m_extant);
CEntity::m_AttributeTable["traits.corpse"] = getoffset(m_corpse);
CEntity::m_AttributeTable["actions.move.turningradius"] = getoffset(m_turningRadius);
CEntity::m_AttributeTable["traits.health.curr"] = getoffset(m_healthCurr);
CEntity::m_AttributeTable["traits.health.max"] = getoffset(m_healthMax);
CEntity::m_AttributeTable["traits.health.regen_rate"] = getoffset(m_healthRegenRate);
CEntity::m_AttributeTable["traits.health.regen_start"] = getoffset(m_healthRegenStart);
CEntity::m_AttributeTable["traits.health.decay_rate"] = getoffset(m_healthDecayRate);
//This are not changable from techs until the updated bars are finished
/* CEntity::m_AttributeTable["traits.stamina.curr"] = getoffset(m_staminaCurr);
CEntity::m_AttributeTable["traits.stamina.max"] = getoffset(m_staminaMax);
CEntity::m_AttributeTable["traits.bars.height"] = getoffset(m_barHeight);
CEntity::m_AttributeTable["traits.bars"] = getoffset(m_barOffset);
CEntity::m_AttributeTable["traits.bars.width"] = getoffset(m_barWidth);
CEntity::m_AttributeTable["traits.bars.border_height"] = getoffset(m_barBorderHeight);
CEntity::m_AttributeTable["traits.bars.border_width"] = getoffset(m_barBorderWidth);
CEntity::m_AttributeTable["traits.bars.border_name"] = getoffset(m_barBorderName);*/
CEntity::m_AttributeTable["traits.flank_penalty.sectors"] = getoffset(m_sectorDivs);
CEntity::m_AttributeTable["traits.pitch.sectors"] = getoffset(m_pitchDivs);
CEntity::m_AttributeTable["traits.rank.width"] = getoffset(m_rankWidth);
// CEntity::m_AttributeTable["traits.rank"] = getoffset(m_rankOffset);
CEntity::m_AttributeTable["traits.rank.height"] = getoffset(m_rankHeight);
CEntity::m_AttributeTable["traits.rank.name"] = getoffset(m_rankName);
CEntity::m_AttributeTable["traits.minimap.type"] = getoffset(m_minimapType);
CEntity::m_AttributeTable["traits.minimap.red"] = getoffset(m_minimapR);
CEntity::m_AttributeTable["traits.minimap.green"] = getoffset(m_minimapG);
CEntity::m_AttributeTable["traits.minimap.blue"] = getoffset(m_minimapB);
CEntity::m_AttributeTable["traits.anchor.type"] = getoffset(m_anchorType);
CEntity::m_AttributeTable["traits.anchor.conformx"] = getoffset(m_anchorConformX);
CEntity::m_AttributeTable["traits.anchor.conformz"] = getoffset(m_anchorConformZ);
CEntity::m_AttributeTable["traits.vision.los"] = getoffset(m_los);
CEntity::m_AttributeTable["traits.vision.permanent"] = getoffset(m_permanent);
CEntity::m_AttributeTable["last_combat_time"] = getoffset(m_lastCombatTime);
CEntity::m_AttributeTable["last_run_time"] = getoffset(m_lastRunTime);
CEntity::m_AttributeTable["building"] = getoffset(m_building);
#undef getoffset
}
void CEntity::kill()
{
g_Selection.removeAll( me );
@ -1386,6 +1442,7 @@ void CEntity::ScriptingInit()
AddMethod<jsval, &CEntity::RegisterOrderChange>( "registerOrderChange", 0 );
AddMethod<jsval, &CEntity::GetAttackDirections>( "getAttackDirections", 0 );
AddMethod<jsval, &CEntity::FindSector>("findSector", 4);
AddMethod<jsval, &CEntity::GetHeight>("getHeight", 0 );
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
AddClassProperty( L"traits.id.classes", (GetFn)&CEntity::getClassSet, (SetFn)&CEntity::setClassSet );

View File

@ -65,6 +65,9 @@ public:
// Intrinsic properties
CBaseEntity* m_base;
//Attributes table: key=attribute, value=variable name
static std::map<CStr, size_t> m_AttributeTable;
// The entity to switch to when this dies.
CStrW m_corpse;
@ -306,6 +309,7 @@ public:
// Reset properties after the entity-template we use changes.
void loadBase();
static void initAttributes(const CEntity* _this);
void playerChanged(); // Fixes player colour if player is changed by script
void reorient(); // Orientation
@ -404,7 +408,10 @@ public:
m_orderQueue.pop_front();
return JSVAL_VOID;
}
jsval GetHeight( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return ToJSVal(m_position.Y);
}
static void ScriptingInit();
private: