82f3bee86b2ab85929242cd103a543f276d954cf
[blender-staging.git] / source / gameengine / GameLogic / SCA_PropertySensor.cpp
1 /*
2  * Property sensor
3  *
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 /** \file gameengine/GameLogic/SCA_PropertySensor.cpp
32  *  \ingroup gamelogic
33  */
34
35
36 #include <stddef.h>
37
38 #include <iostream>
39 #include "SCA_PropertySensor.h"
40 #include "EXP_Operator2Expr.h"
41 #include "EXP_ConstExpr.h"
42 #include "EXP_InputParser.h"
43 #include "EXP_StringValue.h"
44 #include "SCA_EventManager.h"
45 #include "SCA_LogicManager.h"
46 #include "EXP_BoolValue.h"
47 #include "EXP_FloatValue.h"
48 #include <stdio.h>
49
50 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
51                                                                          SCA_IObject* gameobj,
52                                                                          const STR_String& propname,
53                                                                          const STR_String& propval,
54                                                                          const STR_String& propmaxval,
55                                                                          KX_PROPSENSOR_TYPE checktype)
56         : SCA_ISensor(gameobj,eventmgr),
57           m_checktype(checktype),
58           m_checkpropval(propval),
59           m_checkpropmaxval(propmaxval),
60           m_checkpropname(propname)
61 {
62         //CParser pars;
63         //pars.SetContext(this->AddRef());
64         //CValue* resultval = m_rightexpr->Calculate();
65
66         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
67         if (!orgprop->IsError())
68         {
69                 m_previoustext = orgprop->GetText();
70         }
71         orgprop->Release();
72
73         Init();
74 }
75
76 void SCA_PropertySensor::Init()
77 {
78         m_recentresult = false;
79         m_lastresult = m_invert?true:false;
80         m_reset = true;
81 }
82
83 CValue* SCA_PropertySensor::GetReplica()
84 {
85         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
86         // m_range_expr must be recalculated on replica!
87         replica->ProcessReplica();
88         replica->Init();
89         
90         return replica;
91 }
92
93
94
95 bool SCA_PropertySensor::IsPositiveTrigger()
96 {
97         bool result = m_recentresult;//CheckPropertyCondition();
98         if (m_invert)
99                 result = !result;
100
101         return result;
102 }
103
104
105
106 SCA_PropertySensor::~SCA_PropertySensor()
107 {
108 }
109
110
111
112 bool SCA_PropertySensor::Evaluate()
113 {
114         bool result = CheckPropertyCondition();
115         bool reset = m_reset && m_level;
116         
117         m_reset = false;
118         if (m_lastresult!=result)
119         {
120                 m_lastresult = result;
121                 return true;
122         }
123         return (reset) ? true : false;
124 }
125
126
127 bool    SCA_PropertySensor::CheckPropertyCondition()
128 {
129         m_recentresult=false;
130         bool result=false;
131         bool reverse = false;
132         switch (m_checktype)
133         {
134         case KX_PROPSENSOR_NOTEQUAL:
135                 reverse = true;
136                 /* fall-through */
137         case KX_PROPSENSOR_EQUAL:
138                 {
139                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
140                         if (!orgprop->IsError())
141                         {
142                                 const STR_String& testprop = orgprop->GetText();
143                                 // Force strings to upper case, to avoid confusion in
144                                 // bool tests. It's stupid the prop's identity is lost
145                                 // on the way here...
146                                 if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) {
147                                         m_checkpropval.Upper();
148                                 }
149                                 result = (testprop == m_checkpropval);
150                                 
151                                 /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000"
152                                  * this could be made into a generic Value class function for comparing values with a string.
153                                  */
154                                 if (result==false && (orgprop->GetValueType() == VALUE_FLOAT_TYPE)) {
155                                         float f;
156                                         if (sscanf(m_checkpropval.ReadPtr(), "%f", &f) == 1) {
157                                                 result = (f == ((CFloatValue *)orgprop)->GetFloat());
158                                         } 
159                                         else {
160                                                 /* error */
161                                         }
162                                 }
163                                 /* end patch */
164                         }
165                         orgprop->Release();
166
167                         if (reverse)
168                                 result = !result;
169                         break;
170
171                 }
172
173         case KX_PROPSENSOR_EXPRESSION:
174                 {
175 #if 0
176                         if (m_rightexpr)
177                         {
178                                 CValue* resultval = m_rightexpr->Calculate();
179                                 if (resultval->IsError())
180                                 {
181                                         int i=0;
182                                         STR_String errortest = resultval->GetText();
183                                         printf(errortest);
184
185                                 } else
186                                 {
187                                         result = resultval->GetNumber() != 0;
188                                 }
189                         }
190 #endif
191                         break;
192                 }
193         case KX_PROPSENSOR_INTERVAL:
194                 {
195                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
196                         if (!orgprop->IsError())
197                         {
198                                 const float min = m_checkpropval.ToFloat();
199                                 const float max = m_checkpropmaxval.ToFloat();
200                                 float val;
201
202                                 if (orgprop->GetValueType() == VALUE_STRING_TYPE){
203                                         val = orgprop->GetText().ToFloat();
204                                 }
205                                 else {
206                                         val = orgprop->GetNumber();
207                                 }
208
209                                 result = (min <= val) && (val <= max);
210                         }
211                         orgprop->Release();
212
213                 break;
214                 }
215         case KX_PROPSENSOR_CHANGED:
216                 {
217                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
218                                 
219                         if (!orgprop->IsError())
220                         {
221                                 if (m_previoustext != orgprop->GetText())
222                                 {
223                                         m_previoustext = orgprop->GetText();
224                                         result = true;
225                                 }
226                         }
227                         orgprop->Release();
228
229                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
230                         break;
231                 }
232         case KX_PROPSENSOR_LESSTHAN:
233                 reverse = true;
234                 /* fall-through */
235         case KX_PROPSENSOR_GREATERTHAN:
236                 {
237                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
238                         if (!orgprop->IsError())
239                         {
240                                 const float ref = m_checkpropval.ToFloat();
241                                 float val;
242
243                                 if (orgprop->GetValueType() == VALUE_STRING_TYPE){
244                                         val = orgprop->GetText().ToFloat();
245                                 }
246                                 else {
247                                         val = orgprop->GetNumber();
248                                 }
249
250                                 if (reverse) {
251                                         result = val < ref;
252                                 }
253                                 else {
254                                         result = val > ref;
255                                 }
256
257                         }
258                         orgprop->Release();
259
260                         break;
261                 }
262         default:
263                 ; /* error */
264         }
265
266         //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
267         //see Game Engine bugtracker [ #3809 ]
268         m_recentresult = result;
269
270         return result;
271 }
272
273 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
274 {
275         return  GetParent()->FindIdentifier(identifiername);
276 }
277
278 #ifdef WITH_PYTHON
279
280 /* ------------------------------------------------------------------------- */
281 /* Python functions                                                          */
282 /* ------------------------------------------------------------------------- */
283
284 int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*)
285 {
286         /* If someone actually do type checking please make sure the 'max' and 'min'
287          * are checked as well (currently they are calling the PrecalculateRangeExpression
288          * function directly */
289
290         /*  There is no type checking at this moment, unfortunately...           */
291         return 0;
292 }
293
294 /* Integration hooks ------------------------------------------------------- */
295 PyTypeObject SCA_PropertySensor::Type = {
296         PyVarObject_HEAD_INIT(NULL, 0)
297         "SCA_PropertySensor",
298         sizeof(PyObjectPlus_Proxy),
299         0,
300         py_base_dealloc,
301         0,
302         0,
303         0,
304         0,
305         py_base_repr,
306         0,0,0,0,0,0,0,0,0,
307         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
308         0,0,0,0,0,0,0,
309         Methods,
310         0,
311         0,
312         &SCA_ISensor::Type,
313         0,0,0,0,0,0,
314         py_base_new
315 };
316
317 PyMethodDef SCA_PropertySensor::Methods[] = {
318         {NULL,NULL} //Sentinel
319 };
320
321 PyAttributeDef SCA_PropertySensor::Attributes[] = {
322         KX_PYATTRIBUTE_INT_RW("mode",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype),
323         KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,MAX_PROP_NAME,false,SCA_PropertySensor,m_checkpropname,CheckProperty),
324         KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty),
325         KX_PYATTRIBUTE_STRING_RW_CHECK("min",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty),
326         KX_PYATTRIBUTE_STRING_RW_CHECK("max",0,100,false,SCA_PropertySensor,m_checkpropmaxval,validValueForProperty),
327         { NULL }        //Sentinel
328 };
329
330 #endif // WITH_PYTHON
331
332 /* eof */