/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include
#include "Technology.h"
#include "TechnologyCollection.h"
#include "ps/CStr.h"
#include "ps/CLogger.h"
#include "scripting/ScriptingHost.h"
#include "ps/XML/Xeromyces.h"
#include "ps/XML/XeroXMB.h"
#include "Entity.h"
#include "EntityTemplate.h"
#include "EntityTemplateCollection.h"
#include "ps/Player.h"
#include "scripting/ScriptableComplex.inl"
#define LOG_CATEGORY L"Techs"
boost::unordered_set CTechnology::m_scriptsLoaded;
CTechnology::CTechnology( const CStrW& name, CPlayer* player )
: m_Name(name), m_player(player)
{
m_researched = false;
m_excluded = false;
m_inProgress = false;
}
bool CTechnology::LoadXml( const VfsPath& pathname )
{
CXeromyces XeroFile;
if (XeroFile.Load(pathname) != 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(CLogger::Error, LOG_CATEGORY, L"CTechnology: XML root was not \"Tech\" in file %ls. Load failed.", pathname.string().c_str() );
return false;
}
XMBElementList RootChildren = Root.GetChildNodes();
bool ret;
for ( int i=0; im_inProgress )
return false;
}
return ( HasReqEntities() && HasReqTechs() );
}
bool CTechnology::HasReqEntities()
{
// Check whether we have ALL the required entities.
std::vector entities;
// m_player->GetControlledEntities(entities);
for ( std::vector::iterator it=m_ReqEntities.begin(); it != m_ReqEntities.end(); it++ )
{
// For each required class, check that we have it
bool got = false;
for( CEntityList::iterator it2=entities.begin(); it2 != entities.end(); it2++ )
{
if ( (*it2)->m_classes.IsMember(*it) )
{
got = true;
break;
}
}
if( !got )
return false;
}
return true;
}
bool CTechnology::HasReqTechs()
{
// Check whether we have ANY of the required techs (this is slightly confusing but required for
// the way the tech system is currently planned; ideally we'd have an or in the XML).
if ( m_ReqTechs.size() == 0 )
return true;
for ( std::vector::iterator it=m_ReqTechs.begin(); it != m_ReqTechs.end(); it++ )
{
if ( g_TechnologyCollection.GetTechnology( (CStrW)*it, m_player )->IsResearched() )
{
return true;
}
}
return false;
}
void CTechnology::Apply( CEntity* entity )
{
// Find out if the unit has one of our target classes
bool ok = false;
for ( std::vector::iterator it = m_Targets.begin(); it != m_Targets.end(); it++ )
{
if ( entity->m_classes.IsMember( *it ) )
{
ok = true;
break;
}
}
if( !ok ) return;
// Apply modifiers
for ( std::vector::iterator mod=m_Modifiers.begin(); mod!=m_Modifiers.end(); mod++ )
{
jsval oldVal;
if( entity->GetProperty( g_ScriptingHost.getContext(), mod->attribute, &oldVal ) )
{
float modValue;
if( mod->isPercent )
{
jsval baseVal;
entity->m_base->m_unmodified->GetProperty( g_ScriptingHost.getContext(), mod->attribute, &baseVal );
modValue = ToPrimitive(baseVal) * mod->value / 100.0f;
}
else
{
modValue = mod->value;
}
jsval newVal = ToJSVal( ToPrimitive(oldVal) + modValue );
entity->SetProperty( g_ScriptingHost.GetContext(), mod->attribute, &newVal );
}
}
// Apply sets
for ( std::vector::iterator mod=m_Sets.begin(); mod!=m_Sets.end(); mod++ )
{
jsval newVal = ToJSVal( mod->value );
entity->SetProperty( g_ScriptingHost.GetContext(), mod->attribute, &newVal );
}
}
//JS stuff
void CTechnology::ScriptingInit()
{
AddClassProperty(L"name", &CTechnology::m_Name, true);
AddClassProperty(L"player", &CTechnology::m_player, true);
AddClassProperty(L"generic", &CTechnology::m_Generic, true);
AddClassProperty(L"specific", &CTechnology::m_Specific, true);
AddClassProperty(L"icon", &CTechnology::m_Icon); //GUI might want to change this...?
AddClassProperty(L"icon_cell", &CTechnology::m_IconCell);
AddClassProperty(L"classes", &CTechnology::m_Classes, true);
AddClassProperty(L"history", &CTechnology::m_History, true);
AddClassProperty(L"time", &CTechnology::m_ReqTime); //Techs may upgrade research time and cost of other techs
AddClassProperty(L"in_progress", &CTechnology::m_inProgress);
AddMethod( "applyEffects", 2 );
AddMethod( "isExcluded", 0 );
AddMethod( "isValid", 0 );
AddMethod( "isResearched", 0 );
AddMethod( "getPlayerID", 0 );
CJSComplex::ScriptingInit("Technology");
}
bool CTechnology::ApplyEffects( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
// Unmark ourselves as in progress
m_inProgress = false;
if ( !IsTechValid() )
{
return false;
}
// Disable any paired techs
for ( std::vector::iterator it=m_Pairs.begin(); it != m_Pairs.end(); it++ )
g_TechnologyCollection.GetTechnology(*it, m_player)->SetExclusion(true);
// Disable ourselves so we can't be researched twice
m_excluded = true;
// Mark ourselves as researched
m_researched = true;
// Apply effects to all entities
std::vector entities;
// m_player->GetControlledEntities(entities);
for ( size_t i=0; iGetScript(), &rval, 1, &arg );
}
// Add ourselves to player's researched techs
m_player->AddActiveTech( this );
return true;
}
bool CTechnology::IsValid( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return IsTechValid();
}
bool CTechnology::IsExcluded( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return m_excluded;
}
bool CTechnology::IsResearched( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return IsResearched();
}
size_t CTechnology::GetPlayerID( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return m_player->GetPlayerID();
}