Merged 2.5 -r 20124:21003
[blender.git] / source / gameengine / GameLogic / SCA_PropertySensor.cpp
1 /**
2  * Property sensor
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include <iostream>
33 #include "SCA_PropertySensor.h"
34 #include "Operator2Expr.h"
35 #include "ConstExpr.h"
36 #include "InputParser.h"
37 #include "StringValue.h"
38 #include "SCA_EventManager.h"
39 #include "SCA_LogicManager.h"
40 #include "BoolValue.h"
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
47                                                                          SCA_IObject* gameobj,
48                                                                          const STR_String& propname,
49                                                                          const STR_String& propval,
50                                                                          const STR_String& propmaxval,
51                                                                          KX_PROPSENSOR_TYPE checktype,
52                                                                          PyTypeObject* T )
53         : SCA_ISensor(gameobj,eventmgr,T),
54           m_checktype(checktype),
55           m_checkpropval(propval),
56           m_checkpropmaxval(propmaxval),
57           m_checkpropname(propname),
58           m_range_expr(NULL)
59 {
60         //CParser pars;
61         //pars.SetContext(this->AddRef());
62         //CValue* resultval = m_rightexpr->Calculate();
63
64         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
65         if (!orgprop->IsError())
66         {
67                 m_previoustext = orgprop->GetText();
68         }
69         orgprop->Release();
70
71         if (m_checktype==KX_PROPSENSOR_INTERVAL)
72         {
73                 PrecalculateRangeExpression();
74         }
75         Init();
76 }
77
78 void SCA_PropertySensor::Init()
79 {
80         m_recentresult = false;
81         m_lastresult = m_invert?true:false;
82         m_reset = true;
83 }
84
85 void SCA_PropertySensor::PrecalculateRangeExpression()
86 {
87                 CParser pars;
88                 //The context is needed to retrieve the property at runtime but it creates
89                 //loop of references
90                 pars.SetContext(this->AddRef());
91                 STR_String checkstr = "(" + m_checkpropval + " <= " 
92                                                         + m_checkpropname + ") && ( " 
93                                                         + m_checkpropname + " <= " 
94                                                         + m_checkpropmaxval + ")";
95
96                 m_range_expr = pars.ProcessText(checkstr);
97 }
98
99 // Forced deletion of precalculated range expression to break reference loop
100 // Use this function when you know that you won't use the sensor anymore
101 void SCA_PropertySensor::Delete()
102 {
103         if (m_range_expr)
104         {
105                 m_range_expr->Release();
106                 m_range_expr = NULL;
107         }
108         Release();
109 }
110
111 CValue* SCA_PropertySensor::GetReplica()
112 {
113         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
114         // m_range_expr must be recalculated on replica!
115         replica->ProcessReplica();
116         replica->Init();
117
118         replica->m_range_expr = NULL;
119         if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
120         {
121                 replica->PrecalculateRangeExpression();
122         }
123         
124         
125         return replica;
126 }
127
128
129
130 bool SCA_PropertySensor::IsPositiveTrigger()
131 {
132         bool result = m_recentresult;//CheckPropertyCondition();
133         if (m_invert)
134                 result = !result;
135
136         return result;
137 }
138
139
140
141 SCA_PropertySensor::~SCA_PropertySensor()
142 {
143         //if (m_rightexpr)
144         //      m_rightexpr->Release();
145
146         if (m_range_expr)
147         {
148                 m_range_expr->Release();
149                 m_range_expr=NULL;
150         }
151
152 }
153
154
155
156 bool SCA_PropertySensor::Evaluate()
157 {
158         bool result = CheckPropertyCondition();
159         bool reset = m_reset && m_level;
160         
161         m_reset = false;
162         if (m_lastresult!=result)
163         {
164                 m_lastresult = result;
165                 return true;
166         }
167         return (reset) ? true : false;
168 }
169
170
171 bool    SCA_PropertySensor::CheckPropertyCondition()
172 {
173
174         m_recentresult=false;
175         bool result=false;
176         bool reverse = false;
177         switch (m_checktype)
178         {
179         case KX_PROPSENSOR_NOTEQUAL:
180                 reverse = true;
181         case KX_PROPSENSOR_EQUAL:
182                 {
183                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
184                         if (!orgprop->IsError())
185                         {
186                                 const STR_String& testprop = orgprop->GetText();
187                                 // Force strings to upper case, to avoid confusion in
188                                 // bool tests. It's stupid the prop's identity is lost
189                                 // on the way here...
190                                 if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) {
191                                         m_checkpropval.Upper();
192                                 }
193                                 result = (testprop == m_checkpropval);
194                         }
195                         orgprop->Release();
196
197                         if (reverse)
198                                 result = !result;
199                         break;
200
201                 }
202
203         case KX_PROPSENSOR_EXPRESSION:
204                 {
205                         /*
206                         if (m_rightexpr)
207                         {
208                                 CValue* resultval = m_rightexpr->Calculate();
209                                 if (resultval->IsError())
210                                 {
211                                         int i=0;
212                                         STR_String errortest = resultval->GetText();
213                                         printf(errortest);
214
215                                 } else
216                                 {
217                                         result = resultval->GetNumber() != 0;
218                                 }
219                         }
220                         */
221                         break;
222                 }
223         case KX_PROPSENSOR_INTERVAL:
224                 {
225                         //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
226                         //if (orgprop)
227                         //{
228                                 if (m_range_expr)
229                                 {
230                                         CValue* vallie = m_range_expr->Calculate();
231                                         if (vallie)
232                                         {
233                                                 const STR_String& errtext = vallie->GetText();
234                                                 if (&errtext == &CBoolValue::sTrueString)
235                                                 {
236                                                         result = true;
237                                                 } else
238                                                 {
239                                                         if (vallie->IsError())
240                                                         {
241                                                                 //printf (errtext.ReadPtr());
242                                                         } 
243                                                 }
244                                                 
245                                                 vallie->Release();
246                                         }
247                                 }
248
249                                 
250                         //}
251                         
252                 //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
253
254                 break;
255                 }
256         case KX_PROPSENSOR_CHANGED:
257                 {
258                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
259                                 
260                         if (!orgprop->IsError())
261                         {
262                                 if (m_previoustext != orgprop->GetText())
263                                 {
264                                         m_previoustext = orgprop->GetText();
265                                         result = true;
266                                 }
267                         }
268                         orgprop->Release();
269
270                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
271                         break;
272                 }
273         default:
274                 ; /* error */
275         }
276
277         //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
278         //see Game Engine bugtracker [ #3809 ]
279         if (m_checktype != KX_PROPSENSOR_CHANGED)
280         {
281                 m_recentresult=result;
282         } else
283         {
284                 m_recentresult=result;//true;
285         }
286         return result;
287 }
288
289 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
290 {
291         return  GetParent()->FindIdentifier(identifiername);
292 }
293
294 int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*)
295 {
296         /*  There is no type checking at this moment, unfortunately...           */
297         return 0;
298 }
299
300 /* ------------------------------------------------------------------------- */
301 /* Python functions                                                          */
302 /* ------------------------------------------------------------------------- */
303
304 /* Integration hooks ------------------------------------------------------- */
305 PyTypeObject SCA_PropertySensor::Type = {
306 #if (PY_VERSION_HEX >= 0x02060000)
307         PyVarObject_HEAD_INIT(NULL, 0)
308 #else
309         /* python 2.5 and below */
310         PyObject_HEAD_INIT( NULL )  /* required py macro */
311         0,                          /* ob_size */
312 #endif
313         "SCA_PropertySensor",
314         sizeof(PyObjectPlus_Proxy),
315         0,
316         py_base_dealloc,
317         0,
318         0,
319         0,
320         0,
321         py_base_repr,
322         0,0,0,0,0,0,
323         py_base_getattro,
324         py_base_setattro,
325         0,0,0,0,0,0,0,0,0,
326         Methods
327 };
328
329 PyParentObject SCA_PropertySensor::Parents[] = {
330         &SCA_PropertySensor::Type,
331         &SCA_ISensor::Type,
332         &SCA_ILogicBrick::Type,
333         &CValue::Type,
334         NULL
335 };
336
337 PyMethodDef SCA_PropertySensor::Methods[] = {
338         //Deprecated functions ------>
339         {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc},
340         {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc},
341         {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc},
342         {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
343         {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_NOARGS, (PY_METHODCHAR)GetValue_doc},
344         {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, (PY_METHODCHAR)SetValue_doc},
345         //<----- Deprecated
346         {NULL,NULL} //Sentinel
347 };
348
349 PyAttributeDef SCA_PropertySensor::Attributes[] = {
350         KX_PYATTRIBUTE_INT_RW("mode",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype),
351         KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,100,false,SCA_PropertySensor,m_checkpropname,CheckProperty),
352         KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty),
353         { NULL }        //Sentinel
354 };
355
356
357 PyObject* SCA_PropertySensor::py_getattro(PyObject *attr) {
358         py_getattro_up(SCA_ISensor);
359 }
360
361 PyObject* SCA_PropertySensor::py_getattro_dict() {
362         py_getattro_dict_up(SCA_ISensor);
363 }
364
365 int SCA_PropertySensor::py_setattro(PyObject *attr, PyObject *value) {
366         py_setattro_up(SCA_ISensor);
367 }
368
369 /* 1. getType */
370 const char SCA_PropertySensor::GetType_doc[] = 
371 "getType()\n"
372 "\tReturns the type of check this sensor performs.\n";
373 PyObject* SCA_PropertySensor::PyGetType()
374 {
375         ShowDeprecationWarning("getType()", "the mode property");
376         return PyInt_FromLong(m_checktype);
377 }
378
379 /* 2. setType */
380 const char SCA_PropertySensor::SetType_doc[] = 
381 "setType(type)\n"
382 "\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n"
383 "\t        KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n"
384 "\t        or KX_PROPSENSOR_EXPRESSION.\n"
385 "\tSet the type of check to perform.\n";
386 PyObject* SCA_PropertySensor::PySetType(PyObject* args) 
387 {
388         ShowDeprecationWarning("setType()", "the mode property");
389         int typeArg;
390         
391         if (!PyArg_ParseTuple(args, "i:setType", &typeArg)) {
392                 return NULL;
393         }
394         
395         if ( (typeArg > KX_PROPSENSOR_NODEF) 
396                  && (typeArg < KX_PROPSENSOR_MAX) ) {
397                 m_checktype =  typeArg;
398         }
399         
400         Py_RETURN_NONE;
401 }
402
403 /* 3. getProperty */
404 const char SCA_PropertySensor::GetProperty_doc[] = 
405 "getProperty()\n"
406 "\tReturn the property with which the sensor operates.\n";
407 PyObject* SCA_PropertySensor::PyGetProperty() 
408 {
409         ShowDeprecationWarning("getProperty()", "the 'propName' property");
410         return PyString_FromString(m_checkpropname);
411 }
412
413 /* 4. setProperty */
414 const char SCA_PropertySensor::SetProperty_doc[] = 
415 "setProperty(name)\n"
416 "\t- name: string\n"
417 "\tSets the property with which to operate. If there is no property\n"
418 "\tof this name, the call is ignored.\n";
419 PyObject* SCA_PropertySensor::PySetProperty(PyObject* args) 
420 {
421         ShowDeprecationWarning("setProperty()", "the 'propName' property");
422         /* We should query whether the name exists. Or should we create a prop   */
423         /* on the fly?                                                           */
424         char *propNameArg = NULL;
425
426         if (!PyArg_ParseTuple(args, "s:setProperty", &propNameArg)) {
427                 return NULL;
428         }
429
430         CValue *prop = FindIdentifier(STR_String(propNameArg));
431         if (!prop->IsError()) {
432                 m_checkpropname = propNameArg;
433         } else {
434                 ; /* error: bad property name */
435         }
436         prop->Release();
437         Py_RETURN_NONE;
438 }
439
440 /* 5. getValue */
441 const char SCA_PropertySensor::GetValue_doc[] = 
442 "getValue()\n"
443 "\tReturns the value with which the sensor operates.\n";
444 PyObject* SCA_PropertySensor::PyGetValue() 
445 {
446         ShowDeprecationWarning("getValue()", "the value property");
447         return PyString_FromString(m_checkpropval);
448 }
449
450 /* 6. setValue */
451 const char SCA_PropertySensor::SetValue_doc[] = 
452 "setValue(value)\n"
453 "\t- value: string\n"
454 "\tSet the value with which the sensor operates. If the value\n"
455 "\tis not compatible with the type of the property, the subsequent\n"
456 "\t action is ignored.\n";
457 PyObject* SCA_PropertySensor::PySetValue(PyObject* args) 
458 {
459         ShowDeprecationWarning("setValue()", "the value property");
460         /* Here, we need to check whether the value is 'valid' for this property.*/
461         /* We know that the property exists, or is NULL.                         */
462         char *propValArg = NULL;
463
464         if(!PyArg_ParseTuple(args, "s:setValue", &propValArg)) {
465                 return NULL;
466         }
467         STR_String oldval = m_checkpropval;
468         m_checkpropval = propValArg;
469         if (validValueForProperty(m_proxy, NULL)) {
470                 m_checkpropval = oldval;
471                 return NULL;
472         }       
473         Py_RETURN_NONE;
474 }
475
476 /* eof */