Python 2.4 should build with the game engine now, no thanks to python for switching...
[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
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
46                                                                          SCA_IObject* gameobj,
47                                                                          const STR_String& propname,
48                                                                          const STR_String& propval,
49                                                                          const STR_String& propmaxval,
50                                                                          KX_PROPSENSOR_TYPE checktype,
51                                                                          PyTypeObject* T )
52         : SCA_ISensor(gameobj,eventmgr,T),
53           m_checktype(checktype),
54           m_checkpropval(propval),
55           m_checkpropmaxval(propmaxval),
56           m_checkpropname(propname),
57           m_range_expr(NULL)
58 {
59         //CParser pars;
60         //pars.SetContext(this->AddRef());
61         //CValue* resultval = m_rightexpr->Calculate();
62
63         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
64         if (!orgprop->IsError())
65         {
66                 m_previoustext = orgprop->GetText();
67         }
68         orgprop->Release();
69
70         if (m_checktype==KX_PROPSENSOR_INTERVAL)
71         {
72                 PrecalculateRangeExpression();
73         }
74         Init();
75 }
76
77 void SCA_PropertySensor::Init()
78 {
79         m_recentresult = false;
80         m_lastresult = m_invert?true:false;
81         m_reset = true;
82 }
83
84 void SCA_PropertySensor::PrecalculateRangeExpression()
85 {
86                 CParser pars;
87                 //The context is needed to retrieve the property at runtime but it creates
88                 //loop of references
89                 pars.SetContext(this->AddRef());
90                 STR_String checkstr = "(" + m_checkpropval + " <= " 
91                                                         + m_checkpropname + ") && ( " 
92                                                         + m_checkpropname + " <= " 
93                                                         + m_checkpropmaxval + ")";
94
95                 m_range_expr = pars.ProcessText(checkstr);
96 }
97
98 // Forced deletion of precalculated range expression to break reference loop
99 // Use this function when you know that you won't use the sensor anymore
100 void SCA_PropertySensor::Delete()
101 {
102         if (m_range_expr)
103         {
104                 m_range_expr->Release();
105                 m_range_expr = NULL;
106         }
107         Release();
108 }
109
110 CValue* SCA_PropertySensor::GetReplica()
111 {
112         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
113         // m_range_expr must be recalculated on replica!
114         CValue::AddDataToReplica(replica);
115         replica->Init();
116
117         replica->m_range_expr = NULL;
118         if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
119         {
120                 replica->PrecalculateRangeExpression();
121         }
122         
123         
124         return replica;
125 }
126
127
128
129 bool SCA_PropertySensor::IsPositiveTrigger()
130 {
131         bool result = m_recentresult;//CheckPropertyCondition();
132         if (m_invert)
133                 result = !result;
134
135         return result;
136 }
137
138
139
140 SCA_PropertySensor::~SCA_PropertySensor()
141 {
142         //if (m_rightexpr)
143         //      m_rightexpr->Release();
144
145         if (m_range_expr)
146         {
147                 m_range_expr->Release();
148                 m_range_expr=NULL;
149         }
150
151 }
152
153
154
155 bool SCA_PropertySensor::Evaluate(CValue* event)
156 {
157         bool result = CheckPropertyCondition();
158         bool reset = m_reset && m_level;
159         
160         m_reset = false;
161         if (m_lastresult!=result)
162         {
163                 m_lastresult = result;
164                 return true;
165         }
166         return (reset) ? true : false;
167 }
168
169
170 bool    SCA_PropertySensor::CheckPropertyCondition()
171 {
172
173         m_recentresult=false;
174         bool result=false;
175         bool reverse = false;
176         switch (m_checktype)
177         {
178         case KX_PROPSENSOR_NOTEQUAL:
179                 reverse = true;
180         case KX_PROPSENSOR_EQUAL:
181                 {
182                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
183                         if (!orgprop->IsError())
184                         {
185                                 STR_String testprop = orgprop->GetText();
186                                 // Force strings to upper case, to avoid confusion in
187                                 // bool tests. It's stupid the prop's identity is lost
188                                 // on the way here...
189                                 if ((testprop == "TRUE") || (testprop == "FALSE")) {
190                                         STR_String checkprop = m_checkpropval;
191                                         checkprop.Upper();
192                                         result = (testprop == checkprop);
193                                 } else {
194                                         result = (orgprop->GetText() == m_checkpropval);
195                                 }
196                         }
197                         orgprop->Release();
198
199                         if (reverse)
200                                 result = !result;
201                         break;
202
203                 }
204
205         case KX_PROPSENSOR_EXPRESSION:
206                 {
207                         /*
208                         if (m_rightexpr)
209                         {
210                                 CValue* resultval = m_rightexpr->Calculate();
211                                 if (resultval->IsError())
212                                 {
213                                         int i=0;
214                                         STR_String errortest = resultval->GetText();
215                                         printf(errortest);
216
217                                 } else
218                                 {
219                                         result = resultval->GetNumber() != 0;
220                                 }
221                         }
222                         */
223                         break;
224                 }
225         case KX_PROPSENSOR_INTERVAL:
226                 {
227                         //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
228                         //if (orgprop)
229                         //{
230                                 if (m_range_expr)
231                                 {
232                                         CValue* vallie = m_range_expr->Calculate();
233                                         if (vallie)
234                                         {
235                                                 STR_String errtext = vallie->GetText();
236                                                 if (errtext == "TRUE")
237                                                 {
238                                                         result = true;
239                                                 } else
240                                                 {
241                                                         if (vallie->IsError())
242                                                         {
243                                                                 //printf (errtext.ReadPtr());
244                                                         } 
245                                                 }
246                                                 
247                                                 vallie->Release();
248                                         }
249                                 }
250
251                                 
252                         //}
253                         
254                 //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
255
256                 break;
257                 }
258         case KX_PROPSENSOR_CHANGED:
259                 {
260                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
261                                 
262                         if (!orgprop->IsError())
263                         {
264                                 if (m_previoustext != orgprop->GetText())
265                                 {
266                                         m_previoustext = orgprop->GetText();
267                                         result = true;
268                                 }
269                         }
270                         orgprop->Release();
271
272                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
273                         break;
274                 }
275         default:
276                 ; /* error */
277         }
278
279         //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
280         //see Game Engine bugtracker [ #3809 ]
281         if (m_checktype != KX_PROPSENSOR_CHANGED)
282         {
283                 m_recentresult=result;
284         } else
285         {
286                 m_recentresult=result;//true;
287         }
288         return result;
289 }
290
291 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
292 {
293         return  GetParent()->FindIdentifier(identifiername);
294 }
295
296 bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop)
297 {
298         bool result = true;
299         /*  There is no type checking at this moment, unfortunately...           */
300         return result;
301 }
302
303 /* ------------------------------------------------------------------------- */
304 /* Python functions                                                          */
305 /* ------------------------------------------------------------------------- */
306
307 /* Integration hooks ------------------------------------------------------- */
308 PyTypeObject SCA_PropertySensor::Type = {
309         PyObject_HEAD_INIT(&PyType_Type)
310         0,
311         "SCA_PropertySensor",
312         sizeof(SCA_PropertySensor),
313         0,
314         PyDestructor,
315         0,
316         __getattr,
317         __setattr,
318         0, //&MyPyCompare,
319         __repr,
320         0, //&cvalue_as_number,
321         0,
322         0,
323         0,
324         0
325 };
326
327 PyParentObject SCA_PropertySensor::Parents[] = {
328         &SCA_PropertySensor::Type,
329         &SCA_ISensor::Type,
330         &SCA_ILogicBrick::Type,
331         &CValue::Type,
332         NULL
333 };
334
335 PyMethodDef SCA_PropertySensor::Methods[] = {
336         {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc},
337         {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc},
338         {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc},
339         {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
340         {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, (PY_METHODCHAR)GetValue_doc},
341         {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, (PY_METHODCHAR)SetValue_doc},
342         {NULL,NULL} //Sentinel
343 };
344
345 PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) {
346         _getattr_up(SCA_ISensor); /* implicit return! */
347 }
348
349 /* 1. getType */
350 const char SCA_PropertySensor::GetType_doc[] = 
351 "getType()\n"
352 "\tReturns the type of check this sensor performs.\n";
353 PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
354 {
355         return PyInt_FromLong(m_checktype);
356 }
357
358 /* 2. setType */
359 const char SCA_PropertySensor::SetType_doc[] = 
360 "setType(type)\n"
361 "\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n"
362 "\t        KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n"
363 "\t        or KX_PROPSENSOR_EXPRESSION.\n"
364 "\tSet the type of check to perform.\n";
365 PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject* kwds) 
366 {
367         int typeArg;
368         
369         if (!PyArg_ParseTuple(args, "i", &typeArg)) {
370                 return NULL;
371         }
372         
373         if ( (typeArg > KX_PROPSENSOR_NODEF) 
374                  && (typeArg < KX_PROPSENSOR_MAX) ) {
375                 m_checktype =  typeArg;
376         }
377         
378         Py_Return;
379 }
380
381 /* 3. getProperty */
382 const char SCA_PropertySensor::GetProperty_doc[] = 
383 "getProperty()\n"
384 "\tReturn the property with which the sensor operates.\n";
385 PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
386 {
387         return PyString_FromString(m_checkpropname);
388 }
389
390 /* 4. setProperty */
391 const char SCA_PropertySensor::SetProperty_doc[] = 
392 "setProperty(name)\n"
393 "\t- name: string\n"
394 "\tSets the property with which to operate. If there is no property\n"
395 "\tof this name, the call is ignored.\n";
396 PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
397 {
398         /* We should query whether the name exists. Or should we create a prop   */
399         /* on the fly?                                                           */
400         char *propNameArg = NULL;
401
402         if (!PyArg_ParseTuple(args, "s", &propNameArg)) {
403                 return NULL;
404         }
405
406         CValue *prop = FindIdentifier(STR_String(propNameArg));
407         if (!prop->IsError()) {
408                 m_checkpropname = propNameArg;
409         } else {
410                 ; /* error: bad property name */
411         }
412         prop->Release();
413         Py_Return;
414 }
415
416 /* 5. getValue */
417 const char SCA_PropertySensor::GetValue_doc[] = 
418 "getValue()\n"
419 "\tReturns the value with which the sensor operates.\n";
420 PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) 
421 {
422         return PyString_FromString(m_checkpropval);
423 }
424
425 /* 6. setValue */
426 const char SCA_PropertySensor::SetValue_doc[] = 
427 "setValue(value)\n"
428 "\t- value: string\n"
429 "\tSet the value with which the sensor operates. If the value\n"
430 "\tis not compatible with the type of the property, the subsequent\n"
431 "\t action is ignored.\n";
432 PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObject* kwds) 
433 {
434         /* Here, we need to check whether the value is 'valid' for this property.*/
435         /* We know that the property exists, or is NULL.                         */
436         char *propValArg = NULL;
437
438         if(!PyArg_ParseTuple(args, "s", &propValArg)) {
439                 return NULL;
440         }
441
442         if (validValueForProperty(propValArg, m_checkpropname)) {
443                 m_checkpropval = propValArg;
444         }       
445
446         Py_Return;
447 }
448
449 /* eof */