#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" #include "BaseEntity.h" #define LOG_CATEGORY "Techs" STL_HASH_SET CBaseTech::m_scriptsLoaded; CBaseTech::CBaseTech() { ONCE( ScriptingInit(); ); m_researched = m_excluded=false; m_effectFunction = NULL; m_JSFirst = false; } 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; iSetFunction( 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* entities = m_player->GetControlledEntities(); for ( std::vector::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=true; for ( std::vector::iterator it=m_ReqTechs.begin(); it != m_ReqTechs.end(); it++ ) { if ( !g_BaseTechCollection.getTemplate( (CStrW)*it )->isResearched() ) { ret=false; break; } } return ret; } //JS stuff void CBaseTech::ScriptingInit() { 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(L"icon_cell", &CBaseTech::m_IconCell); AddProperty(L"classes", &CBaseTech::m_Classes, true); AddProperty(L"history", &CBaseTech::m_History, true); AddProperty(L"time", &CBaseTech::m_ReqTime); //Techs may upgrade research time and cost of other techs AddProperty(L"food", &CBaseTech::m_ReqFood); AddProperty(L"wood", &CBaseTech::m_ReqWood); AddProperty(L"stone", &CBaseTech::m_ReqStone); AddProperty(L"ore", &CBaseTech::m_ReqOre); AddMethod( "applyEffects", 1 ); AddMethod( "isExcluded", 0 ); AddMethod( "isValid", 0 ); AddMethod( "isResearched", 0 ); AddMethod( "getPlayerID", 0 ); AddMethod( "isJSFirst", 0 ); CJSObject::ScriptingInit("TechTemplate"); debug_printf("CBaseTech::ScriptingInit complete"); } 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( argv[0] ); bool invert = ToPrimitive( 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( argv[2] ); if ( first ) if( m_effectFunction ) m_effectFunction->Run( this->GetScript() ); //Disable other templates for ( std::vector::iterator it=m_Pairs.begin(); it != m_Pairs.end(); it++ ) g_BaseTechCollection.getTemplate(*it)->setExclusion(true); std::vector* entities = m_player->GetControlledEntities(); if ( entities->empty() ) { delete entities; return JS_FALSE; } std::vector entitiesAffected; //Find which entities should be affected for ( size_t i=0; isize(); ++i ) { for ( std::vector::iterator it = m_Targets.begin(); it != m_Targets.end(); it++ ) { if ( (*entities)[i]->m_classes.IsMember( *it ) ) { entitiesAffected.push_back( (*entities)[i] ); break; } } } std::vector::iterator HEit = entitiesAffected.begin(); for ( ; HEit != entitiesAffected.end(); HEit++ ) { for ( std::vector::iterator mod=m_Modifiers.begin(); mod!=m_Modifiers.end(); mod++ ) { //CEntity* ent = *HEit; //debug_printf("Modifying on %ls\n", ent->m_base->m_Tag.c_str() ); //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 = entitiesAffected.begin(); HEit != entitiesAffected.end(); HEit++ ) { for ( std::vector::iterator set=m_Sets.begin(); set!=m_Sets.end(); set++ ) { //CEntity* ent = *HEit; //debug_printf("Setting on %ls\n", ent->m_base->m_Tag.c_str() ); //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 ) if( m_effectFunction ) m_effectFunction->Run( this->GetScript() ); delete entities; debug_printf("Done! I think\n"); 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; }