#include "precompiled.h" #include "Technology.h" #include "TechnologyCollection.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" #include "Entity.h" #include "EntityTemplate.h" #include "EntityTemplateCollection.h" #include "ps/Player.h" #include "scripting/ScriptableComplex.inl" #define LOG_CATEGORY "Techs" STL_HASH_SET CTechnology::m_scriptsLoaded; CTechnology::CTechnology( const CStrW& name, CPlayer* player ) : m_Name(name), m_player(player) { ONCE( ScriptingInit(); ); m_researched=false; m_excluded = false; m_inProgress = false; } bool CTechnology::loadXML( const 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, "CTechnology: 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; im_inProgress ) return false; } return ( hasReqEntities() && hasReqTechs() ); } bool CTechnology::hasReqEntities() { // Check whether we have ALL the required entities. std::vector* entities = m_player->GetControlledEntities(); 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 ) { delete entities; return false; } } delete entities; 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() { AddProperty(L"name", &CTechnology::m_Name, true); AddProperty(L"player", &CTechnology::m_player, true); AddProperty(L"generic", &CTechnology::m_Generic, true); AddProperty(L"specific", &CTechnology::m_Specific, true); AddProperty(L"icon", &CTechnology::m_Icon); //GUI might want to change this...? AddProperty(L"icon_cell", &CTechnology::m_IconCell); AddProperty(L"classes", &CTechnology::m_Classes, true); AddProperty(L"history", &CTechnology::m_History, true); AddProperty(L"time", &CTechnology::m_ReqTime); //Techs may upgrade research time and cost of other techs AddProperty(L"food", &CTechnology::m_ReqFood); AddProperty(L"wood", &CTechnology::m_ReqWood); AddProperty(L"stone", &CTechnology::m_ReqStone); AddProperty(L"metal", &CTechnology::m_ReqMetal); AddProperty(L"in_progress", &CTechnology::m_inProgress); AddMethod( "applyEffects", 2 ); AddMethod( "isExcluded", 0 ); AddMethod( "isValid", 0 ); AddMethod( "isResearched", 0 ); AddMethod( "getPlayerID", 0 ); CJSObject::ScriptingInit("Technology"); } jsval CTechnology::ApplyEffects( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { // Unmark ourselves as in progress m_inProgress = false; if ( !isTechValid() ) { return JSVAL_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(); for ( size_t i=0; isize(); ++i ) { apply( (*entities)[i] ); } delete entities; // Run one-time tech script if( m_effectFunction ) { jsval rval; jsval arg = ToJSVal( m_player ); m_effectFunction.Run( this->GetScript(), &rval, 1, &arg ); } // Add ourselves to player's researched techs m_player->AddActiveTech( this ); return JSVAL_TRUE; } jsval CTechnology::IsValid( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { return ToJSVal( isTechValid() ); } jsval CTechnology::IsExcluded( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { return ToJSVal( m_excluded ); } jsval CTechnology::IsResearched( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { return ToJSVal( isResearched() ); } inline jsval CTechnology::GetPlayerID( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { return ToJSVal( m_player->GetPlayerID() ); }