Blender  V2.59
SCA_PropertySensor.cpp
Go to the documentation of this file.
00001 /*
00002  * Property sensor
00003  *
00004  * $Id: SCA_PropertySensor.cpp 35169 2011-02-25 13:32:11Z jesterking $
00005  *
00006  * ***** BEGIN GPL LICENSE BLOCK *****
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software Foundation,
00020  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021  *
00022  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00023  * All rights reserved.
00024  *
00025  * The Original Code is: all of this file.
00026  *
00027  * Contributor(s): none yet.
00028  *
00029  * ***** END GPL LICENSE BLOCK *****
00030  */
00031 
00037 #include <stddef.h>
00038 
00039 #include <iostream>
00040 #include "SCA_PropertySensor.h"
00041 #include "Operator2Expr.h"
00042 #include "ConstExpr.h"
00043 #include "InputParser.h"
00044 #include "StringValue.h"
00045 #include "SCA_EventManager.h"
00046 #include "SCA_LogicManager.h"
00047 #include "BoolValue.h"
00048 #include "FloatValue.h"
00049 #include <stdio.h>
00050 
00051 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
00052                                                                          SCA_IObject* gameobj,
00053                                                                          const STR_String& propname,
00054                                                                          const STR_String& propval,
00055                                                                          const STR_String& propmaxval,
00056                                                                          KX_PROPSENSOR_TYPE checktype)
00057         : SCA_ISensor(gameobj,eventmgr),
00058           m_checktype(checktype),
00059           m_checkpropval(propval),
00060           m_checkpropmaxval(propmaxval),
00061           m_checkpropname(propname),
00062           m_range_expr(NULL)
00063 {
00064         //CParser pars;
00065         //pars.SetContext(this->AddRef());
00066         //CValue* resultval = m_rightexpr->Calculate();
00067 
00068         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00069         if (!orgprop->IsError())
00070         {
00071                 m_previoustext = orgprop->GetText();
00072         }
00073         orgprop->Release();
00074 
00075         if (m_checktype==KX_PROPSENSOR_INTERVAL)
00076         {
00077                 PrecalculateRangeExpression();
00078         }
00079         Init();
00080 }
00081 
00082 void SCA_PropertySensor::Init()
00083 {
00084         m_recentresult = false;
00085         m_lastresult = m_invert?true:false;
00086         m_reset = true;
00087 }
00088 
00089 void SCA_PropertySensor::PrecalculateRangeExpression()
00090 {
00091                 CParser pars;
00092                 //The context is needed to retrieve the property at runtime but it creates
00093                 //loop of references
00094                 pars.SetContext(this->AddRef());
00095                 STR_String checkstr = "(" + m_checkpropval + " <= " 
00096                                                         + m_checkpropname + ") && ( " 
00097                                                         + m_checkpropname + " <= " 
00098                                                         + m_checkpropmaxval + ")";
00099 
00100                 m_range_expr = pars.ProcessText(checkstr);
00101 }
00102 
00103 // Forced deletion of precalculated range expression to break reference loop
00104 // Use this function when you know that you won't use the sensor anymore
00105 void SCA_PropertySensor::Delete()
00106 {
00107         if (m_range_expr)
00108         {
00109                 m_range_expr->Release();
00110                 m_range_expr = NULL;
00111         }
00112         Release();
00113 }
00114 
00115 CValue* SCA_PropertySensor::GetReplica()
00116 {
00117         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
00118         // m_range_expr must be recalculated on replica!
00119         replica->ProcessReplica();
00120         replica->Init();
00121 
00122         replica->m_range_expr = NULL;
00123         if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
00124         {
00125                 replica->PrecalculateRangeExpression();
00126         }
00127         
00128         
00129         return replica;
00130 }
00131 
00132 
00133 
00134 bool SCA_PropertySensor::IsPositiveTrigger()
00135 {
00136         bool result = m_recentresult;//CheckPropertyCondition();
00137         if (m_invert)
00138                 result = !result;
00139 
00140         return result;
00141 }
00142 
00143 
00144 
00145 SCA_PropertySensor::~SCA_PropertySensor()
00146 {
00147         //if (m_rightexpr)
00148         //      m_rightexpr->Release();
00149 
00150         if (m_range_expr)
00151         {
00152                 m_range_expr->Release();
00153                 m_range_expr=NULL;
00154         }
00155 
00156 }
00157 
00158 
00159 
00160 bool SCA_PropertySensor::Evaluate()
00161 {
00162         bool result = CheckPropertyCondition();
00163         bool reset = m_reset && m_level;
00164         
00165         m_reset = false;
00166         if (m_lastresult!=result)
00167         {
00168                 m_lastresult = result;
00169                 return true;
00170         }
00171         return (reset) ? true : false;
00172 }
00173 
00174 
00175 bool    SCA_PropertySensor::CheckPropertyCondition()
00176 {
00177 
00178         m_recentresult=false;
00179         bool result=false;
00180         bool reverse = false;
00181         switch (m_checktype)
00182         {
00183         case KX_PROPSENSOR_NOTEQUAL:
00184                 reverse = true;
00185         case KX_PROPSENSOR_EQUAL:
00186                 {
00187                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00188                         if (!orgprop->IsError())
00189                         {
00190                                 const STR_String& testprop = orgprop->GetText();
00191                                 // Force strings to upper case, to avoid confusion in
00192                                 // bool tests. It's stupid the prop's identity is lost
00193                                 // on the way here...
00194                                 if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) {
00195                                         m_checkpropval.Upper();
00196                                 }
00197                                 result = (testprop == m_checkpropval);
00198                                 
00199                                 /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000"
00200                                  * this could be made into a generic Value class function for comparing values with a string.
00201                                  */
00202                                 if(result==false && dynamic_cast<CFloatValue *>(orgprop) != NULL) {
00203                                         float f;
00204                                         
00205                                         if(EOF == sscanf(m_checkpropval.ReadPtr(), "%f", &f))
00206                                         {
00207                                                 //error
00208                                         } 
00209                                         else {
00210                                                 result = (f == ((CFloatValue *)orgprop)->GetFloat());
00211                                         }
00212                                 }
00213                                 /* end patch */
00214                         }
00215                         orgprop->Release();
00216 
00217                         if (reverse)
00218                                 result = !result;
00219                         break;
00220 
00221                 }
00222 
00223         case KX_PROPSENSOR_EXPRESSION:
00224                 {
00225                         /*
00226                         if (m_rightexpr)
00227                         {
00228                                 CValue* resultval = m_rightexpr->Calculate();
00229                                 if (resultval->IsError())
00230                                 {
00231                                         int i=0;
00232                                         STR_String errortest = resultval->GetText();
00233                                         printf(errortest);
00234 
00235                                 } else
00236                                 {
00237                                         result = resultval->GetNumber() != 0;
00238                                 }
00239                         }
00240                         */
00241                         break;
00242                 }
00243         case KX_PROPSENSOR_INTERVAL:
00244                 {
00245                         //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00246                         //if (orgprop)
00247                         //{
00248                                 if (m_range_expr)
00249                                 {
00250                                         CValue* vallie = m_range_expr->Calculate();
00251                                         if (vallie)
00252                                         {
00253                                                 const STR_String& errtext = vallie->GetText();
00254                                                 if (&errtext == &CBoolValue::sTrueString)
00255                                                 {
00256                                                         result = true;
00257                                                 } else
00258                                                 {
00259                                                         if (vallie->IsError())
00260                                                         {
00261                                                                 //printf (errtext.ReadPtr());
00262                                                         } 
00263                                                 }
00264                                                 
00265                                                 vallie->Release();
00266                                         }
00267                                 }
00268 
00269                                 
00270                         //}
00271                         
00272                 //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
00273 
00274                 break;
00275                 }
00276         case KX_PROPSENSOR_CHANGED:
00277                 {
00278                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00279                                 
00280                         if (!orgprop->IsError())
00281                         {
00282                                 if (m_previoustext != orgprop->GetText())
00283                                 {
00284                                         m_previoustext = orgprop->GetText();
00285                                         result = true;
00286                                 }
00287                         }
00288                         orgprop->Release();
00289 
00290                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
00291                         break;
00292                 }
00293         default:
00294                 ; /* error */
00295         }
00296 
00297         //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
00298         //see Game Engine bugtracker [ #3809 ]
00299         if (m_checktype != KX_PROPSENSOR_CHANGED)
00300         {
00301                 m_recentresult=result;
00302         } else
00303         {
00304                 m_recentresult=result;//true;
00305         }
00306         return result;
00307 }
00308 
00309 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
00310 {
00311         return  GetParent()->FindIdentifier(identifiername);
00312 }
00313 
00314 #ifdef WITH_PYTHON
00315 
00316 /* ------------------------------------------------------------------------- */
00317 /* Python functions                                                          */
00318 /* ------------------------------------------------------------------------- */
00319 
00320 int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*)
00321 {
00322         /*  If someone actually do type checking please make sure the 'max' and 'min'
00323                 are checked as well (currently they are calling the PrecalculateRangeExpression
00324                 function directly       */
00325 
00326         /*  There is no type checking at this moment, unfortunately...           */
00327         return 0;
00328 }
00329 
00330 int SCA_PropertySensor::validValueForIntervalProperty(void *self, const PyAttributeDef*)
00331 {
00332         SCA_PropertySensor*     sensor = reinterpret_cast<SCA_PropertySensor*>(self);
00333 
00334         if (sensor->m_checktype==KX_PROPSENSOR_INTERVAL)
00335         {
00336                 sensor->PrecalculateRangeExpression();
00337         }
00338         return 0;
00339 }
00340 
00341 int SCA_PropertySensor::modeChange(void *self, const PyAttributeDef* attrdef)
00342 {
00343         SCA_PropertySensor*     sensor = reinterpret_cast<SCA_PropertySensor*>(self);
00344 
00345         if (sensor->m_checktype==KX_PROPSENSOR_INTERVAL)
00346         {
00347                 sensor->PrecalculateRangeExpression();
00348         }
00349         return 0;
00350 }
00351 
00352 /* Integration hooks ------------------------------------------------------- */
00353 PyTypeObject SCA_PropertySensor::Type = {
00354         PyVarObject_HEAD_INIT(NULL, 0)
00355         "SCA_PropertySensor",
00356         sizeof(PyObjectPlus_Proxy),
00357         0,
00358         py_base_dealloc,
00359         0,
00360         0,
00361         0,
00362         0,
00363         py_base_repr,
00364         0,0,0,0,0,0,0,0,0,
00365         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00366         0,0,0,0,0,0,0,
00367         Methods,
00368         0,
00369         0,
00370         &SCA_ISensor::Type,
00371         0,0,0,0,0,0,
00372         py_base_new
00373 };
00374 
00375 PyMethodDef SCA_PropertySensor::Methods[] = {
00376         {NULL,NULL} //Sentinel
00377 };
00378 
00379 PyAttributeDef SCA_PropertySensor::Attributes[] = {
00380         KX_PYATTRIBUTE_INT_RW_CHECK("mode",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype,modeChange),
00381         KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,100,false,SCA_PropertySensor,m_checkpropname,CheckProperty),
00382         KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty),
00383         KX_PYATTRIBUTE_STRING_RW_CHECK("min",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForIntervalProperty),
00384         KX_PYATTRIBUTE_STRING_RW_CHECK("max",0,100,false,SCA_PropertySensor,m_checkpropmaxval,validValueForIntervalProperty),
00385         { NULL }        //Sentinel
00386 };
00387 
00388 #endif // WITH_PYTHON
00389 
00390 /* eof */